import eventlet
# Force eventlet to be used as the async mode for Flask-SocketIO
eventlet.monkey_patch()
from flask import Flask, render_template, request
from flask_socketio import SocketIO, emit, join_room, leave_room
import backend  # Import backend functions
import matplotlib.pyplot as plt
import base64
from io import BytesIO
import random
import logging

# Configure the logging level
logging.getLogger('eventlet.wsgi.server').setLevel(logging.ERROR)
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
socketio = SocketIO(app, async_mode='eventlet')

exams = backend.load_question_sets()  # Load available exams
selected_questions = []  # Global variable to store the selected questions
current_question = {"index": 0, "answers": {}, "started": False}
participants = {}

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/client')
def client():
    return render_template('client.html')

@app.route('/host')
def host():
    return render_template('host.html', exams=exams)

@socketio.on('join')
def on_join(data):
    username = data['username']
    user_id_number = random.randint(1000, 9999)
    participants[request.sid] = {"user_id_number": user_id_number, "username": username, "score": 0}
    join_room('quiz')
    emit('update_participants', {"participants": participants, "count": len(participants)}, room='quiz')
    print(f"{username} (ID: {user_id_number}) joined the quiz.")

@socketio.on('disconnect')
def on_leave():
    if request.sid in participants:
        username = participants[request.sid]["username"]
        leave_room('quiz')
        del participants[request.sid]
        emit('update_participants', {"participants": participants, "count": len(participants)}, room='quiz')
        print(f"{username} left the quiz.")

@socketio.on('load_quiz')
def load_quiz(data):
    global selected_questions, current_question
    exam_name = data['exam_name']
    start_question = data.get('start_question', 1) - 1  # Default to question 1 if not provided
    selected_questions = backend.select_exam(exam_name)
    if selected_questions:
        num_questions = len(selected_questions)
        current_question['index'] = start_question  # Set the starting question index
        emit('quiz_loaded', {"success": True, "num_questions": num_questions, "start_question": start_question + 1}, room=request.sid)
    else:
        emit('quiz_loaded', {"success": False}, room=request.sid)

@socketio.on('start_quiz')
def start_quiz():
    if participants and selected_questions:
        current_question['started'] = True
        index = current_question['index']
        question = selected_questions[index]
        # Send the starting question to all clients
        emit('new_question', {"question": question["question"], "options": question["options"], "index": index + 1}, room='quiz')
        emit('enable_end_quiz', room=request.sid)  # Enable "End Quiz" for the host




@socketio.on('restart_quiz')
def restart_quiz():
    reset_quiz()
    emit('quiz_reset', room='quiz')
    start_quiz()

@socketio.on('submit_answer')
def receive_answer(data):
    username = participants[request.sid]["username"]
    answer = data['answer']
    current_question['answers'][username] = answer
    print(f"{username} submitted an answer: {answer}")

@socketio.on('check_answers')
def check_answers():
    index = current_question['index']
    if index < len(selected_questions):
        question = selected_questions[index]
        correct_answer = question['correct']
        results = {
            "question": question["question"],
            "answers": current_question["answers"],
            "correct_answer": correct_answer
        }

        chart_base64 = generate_chart(current_question["answers"], question["options"])
        emit('display_results', {"results": results, "chart": chart_base64}, room='quiz')

        for sid, participant in participants.items():
            if current_question['answers'].get(participant["username"]) == correct_answer:
                participants[sid]["score"] += 1

@socketio.on('next_question')
def next_question():
    current_question['index'] += 1
    current_question['answers'] = {}
    if current_question['index'] < len(selected_questions):
        question = selected_questions[current_question['index']]
        emit('clear_results', room='quiz')
        emit('new_question', {"question": question["question"], "options": question["options"], "index": current_question['index'] + 1}, room='quiz')
    else:
        final_results = calculate_final_results()
        emit('display_final_results', final_results, room='quiz')


@socketio.on('end_quiz')
def end_quiz():
    if current_question['started']:  # Ensure the quiz has started before ending it
        final_results = calculate_final_results()
        emit('display_final_results', final_results, room='quiz')
        reset_quiz()  # Reset the quiz state


def generate_chart(answers, options):
    letters = [chr(65 + i) for i in range(len(options))] # Dynamically generate letters for options
    counts = [list(answers.values()).count(option) for option in options]
    plt.figure(figsize=(6, 4))
    plt.bar(letters, counts)
    plt.xlabel('Options')
    plt.ylabel('Number of Votes')
    plt.title('Results')
    buf = BytesIO()
    plt.savefig(buf, format='png')
    buf.seek(0)
    chart_base64 = base64.b64encode(buf.read()).decode('utf-8')
    buf.close()
    plt.close()
    return chart_base64

def calculate_final_results():
    sorted_scores = sorted(participants.values(), key=lambda x: x['score'], reverse=True)
    return [{"username": p["username"], "score": p["score"]} for p in sorted_scores]

def reset_quiz():
    global selected_questions, current_question
    current_question = {"index": 0, "answers": {}, "started": False}
    for participant in participants.values():
        participant["score"] = 0

if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=7860, debug=False)