from flask import Blueprint, request, jsonify from backend.models import db, Game, Team from backend.services import game_service from backend.app import socketio from backend.auth.middleware import require_auth bp = Blueprint('admin', __name__, url_prefix='/api/admin') @bp.route('/game//start', methods=['POST']) @require_auth def start_game(game_id): """Start/activate a game""" game = Game.query.get_or_404(game_id) try: game_service.start_game(game, socketio) return jsonify({'message': 'Game started successfully', 'game': game.to_dict()}), 200 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//next', methods=['POST']) @require_auth def next_question(game_id): """Move to next question""" game = Game.query.get_or_404(game_id) try: if game_service.next_question(game, socketio): return jsonify({'message': 'Moved to next question', 'current_index': game.current_question_index}), 200 else: return jsonify({'error': 'Already at last question'}), 400 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//prev', methods=['POST']) @require_auth def previous_question(game_id): """Move to previous question""" game = Game.query.get_or_404(game_id) try: if game_service.previous_question(game, socketio): return jsonify({'message': 'Moved to previous question', 'current_index': game.current_question_index}), 200 else: return jsonify({'error': 'Already at first question'}), 400 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//award', methods=['POST']) @require_auth def award_points(game_id): """Award points to a team Expected JSON: { "team_id": int, "points": int } """ game = Game.query.get_or_404(game_id) data = request.get_json() if not data or 'team_id' not in data or 'points' not in data: return jsonify({'error': 'team_id and points are required'}), 400 team_id = data['team_id'] points = data['points'] team = Team.query.get_or_404(team_id) # Verify team belongs to this game if team.game_id != game_id: return jsonify({'error': 'Team does not belong to this game'}), 400 try: game_service.award_points(game, team, points, socketio) return jsonify({'message': 'Points awarded successfully', 'team': team.to_dict()}), 200 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//current', methods=['GET']) @require_auth def get_current_state(game_id): """Get current game state with answer (admin only)""" game = Game.query.get_or_404(game_id) try: state = game_service.get_admin_game_state(game) return jsonify(state), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/game//toggle-answer', methods=['POST']) @require_auth def toggle_answer_visibility(game_id): """Toggle answer visibility on contestant screen Expected JSON: { "show_answer": bool } """ game = Game.query.get_or_404(game_id) data = request.get_json() if not data or 'show_answer' not in data: return jsonify({'error': 'show_answer is required'}), 400 show_answer = data['show_answer'] try: game_service.toggle_answer_visibility(game, show_answer, socketio) return jsonify({'message': 'Answer visibility toggled', 'show_answer': show_answer}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/game//pause-timer', methods=['POST']) @require_auth def pause_timer(game_id): """Pause or resume the timer Expected JSON: { "paused": bool } """ game = Game.query.get_or_404(game_id) data = request.get_json() if not data or 'paused' not in data: return jsonify({'error': 'paused is required'}), 400 paused = data['paused'] try: game_service.toggle_timer_pause(game, paused, socketio) return jsonify({'message': 'Timer pause state updated', 'paused': paused}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/game//reset-timer', methods=['POST']) @require_auth def reset_timer(game_id): """Reset the timer to 30 seconds""" game = Game.query.get_or_404(game_id) try: game_service.reset_timer(game, socketio) return jsonify({'message': 'Timer reset'}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/game//end', methods=['POST']) @require_auth def end_game(game_id): """End/deactivate a game""" game = Game.query.get_or_404(game_id) try: game_service.end_game(game, socketio) return jsonify({'message': 'Game ended successfully', 'game': game.to_dict()}), 200 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//restart', methods=['POST']) @require_auth def restart_game(game_id): """Restart a game (clear scores and reset to waiting state)""" game = Game.query.get_or_404(game_id) try: game_service.restart_game(game, socketio) return jsonify({'message': 'Game restarted successfully', 'game': game.to_dict()}), 200 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//team//use-lifeline', methods=['POST']) @require_auth def use_lifeline(game_id, team_id): """Use a phone-a-friend lifeline for a team""" game = Game.query.get_or_404(game_id) team = Team.query.get_or_404(team_id) # Verify team belongs to this game if team.game_id != game_id: return jsonify({'error': 'Team does not belong to this game'}), 400 if team.phone_a_friend_count <= 0: return jsonify({'error': 'No lifelines remaining'}), 400 try: team.phone_a_friend_count -= 1 db.session.commit() # Broadcast lifeline update game_service.broadcast_lifeline_update(game, team, socketio) return jsonify({'message': 'Lifeline used', 'team': team.to_dict()}), 200 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//team//add-lifeline', methods=['POST']) @require_auth def add_lifeline(game_id, team_id): """Add a phone-a-friend lifeline to a team""" game = Game.query.get_or_404(game_id) team = Team.query.get_or_404(team_id) # Verify team belongs to this game if team.game_id != game_id: return jsonify({'error': 'Team does not belong to this game'}), 400 try: team.phone_a_friend_count += 1 db.session.commit() # Broadcast lifeline update game_service.broadcast_lifeline_update(game, team, socketio) return jsonify({'message': 'Lifeline added', 'team': team.to_dict()}), 200 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @bp.route('/game//audio/play', methods=['POST']) @require_auth def play_audio(game_id): """Admin controls audio playback for contestants""" game = Game.query.get_or_404(game_id) try: game_service.broadcast_audio_play(game, socketio) return jsonify({'message': 'Audio play command sent'}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/game//audio/pause', methods=['POST']) @require_auth def pause_audio(game_id): """Pause audio for all contestants""" game = Game.query.get_or_404(game_id) try: game_service.broadcast_audio_pause(game, socketio) return jsonify({'message': 'Audio pause command sent'}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/game//audio/stop', methods=['POST']) @require_auth def stop_audio(game_id): """Stop and reset audio for all contestants""" game = Game.query.get_or_404(game_id) try: game_service.broadcast_audio_stop(game, socketio) return jsonify({'message': 'Audio stop command sent'}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/game//audio/seek', methods=['POST']) @require_auth def seek_audio(game_id): """Seek audio to specific position Expected JSON: { "position": float } """ game = Game.query.get_or_404(game_id) data = request.get_json() if not data or 'position' not in data: return jsonify({'error': 'position is required'}), 400 try: position = float(data['position']) game_service.broadcast_audio_seek(game, position, socketio) return jsonify({'message': f'Audio seeked to {position}s'}), 200 except Exception as e: return jsonify({'error': str(e)}), 500