import gradio as gr
import matplotlib as mpl

from quiz import BenchmarkQuiz, BENCHMARKS, QuestionData

mpl.rcParams["figure.dpi"] = 300


def update_quiz_screen(quiz: BenchmarkQuiz, question_data: QuestionData):
    quiz_state = quiz.state
    return {
        quiz_screen: gr.update(visible=True),
        question_number: gr.update(value=question_data.question_num),
        question_text: gr.update(value=question_data.question),
        answer_input: gr.update(
            value=quiz_state.user_answers[quiz_state.current_question],
            choices=question_data.options,
            visible=BENCHMARKS[quiz_state.benchmark_name]["type"] == "multiple_choice",
            label=question_data.instruction,
        ),
        free_text_input: gr.update(
            value=quiz_state.user_answers[quiz_state.current_question],
            visible=BENCHMARKS[quiz_state.benchmark_name]["type"] == "free_text",
            label=question_data.instruction,
        ),
        next_button: gr.update(
            value=question_data.next_button_text,
        ),
        previous_button: gr.update(visible=question_data.previous_button_visibility),
    }


def update_score_screen(plot, results_data):
    updates = {
        score_screen: gr.update(visible=True),
        score_plot: gr.update(value=plot),
        results_container: gr.update(visible=True),
    }
    for i, result in enumerate(results_data):
        updates[result_cards[i]] = gr.update(
            visible=True,
            elem_classes=[
                "correct-answer"
                if result["points"] == 1.0
                else "semi-correct-answer"
                if result["points"] == 0.5
                else "incorrect-answer"
            ],
        )
        emoji = (
            "✅"
            if result["points"] == 1.0
            else "❌"
            if result["points"] == 0.0
            else "🔶"
        )

        markdown_string = f"### {emoji} Spurning {result['question_num']}"
        markdown_string += f"\n{result['question']}"
        markdown_string += (
            f"\n\nValkostir:\n"
            + "\n".join([f"- {option}" for option in result["options"]])
            if result["options"]
            else ""
        )
        markdown_string += f"\n\n**Þitt svar:** {result['user_answer']}"
        markdown_string += f"\n\n**Rétt svar:** {result['correct_answer']}"
        markdown_string += f"\n\n**Stig:** {result['points']}"
        updates[result_cards[i].children[0]] = gr.update(value=markdown_string)

    return updates


def start_quiz_handler(benchmark_name):
    quiz = BenchmarkQuiz()
    quiz.start_quiz(benchmark_name)
    question_data = quiz.update_question()
    return {
        start_screen: gr.update(visible=False),
        score_screen: gr.update(visible=False),
        **update_quiz_screen(quiz, question_data),
        quiz_state: quiz,
    }


def next_question_handler(quiz, answer_input, free_text_input):
    answer = (
        answer_input
        if BENCHMARKS[quiz.state.benchmark_name]["type"] == "multiple_choice"
        else free_text_input
    )
    result = quiz.next_question(answer)
    if result["completed"]:
        return {
            quiz_screen: gr.update(visible=False),
            **update_score_screen(result["plot"], result["results_data"]),
            quiz_state: quiz,
        }
    else:
        return {**update_quiz_screen(quiz, result["question_data"]), quiz_state: quiz}


def previous_question_handler(quiz):
    question_data = quiz.previous_question()
    return {**update_quiz_screen(quiz, question_data), quiz_state: quiz}


def reset_quiz_handler():
    return {
        start_screen: gr.update(visible=True),
        quiz_screen: gr.update(visible=False),
        score_screen: gr.update(visible=False),
        next_button: gr.update(visible=True),
    }


demo = gr.Blocks(
    theme=gr.themes.Soft(),
    title="Mælipróf",
    css="""
    .correct-answer, .correct-answer .block {
        background-color: #d4edda !important;
        border-color: #c3e6cb !important;
    }
    .incorrect-answer, .incorrect-answer .block {
        background-color: #f8d7da !important;
        border-color: #f5c6cb !important;
    }

    .semi-correct-answer, .semi-correct-answer .block {
        background-color: #fff3cd !important;
        border-color: #ffeeba !important;
    }
    .correct-answer, .incorrect-answer, .semi-correct-answer {
        border-radius: 5px;
        padding: 10px;
        margin-bottom: 10px;
    }
    """,
)
with demo:
    start_screen = gr.Column(visible=True)
    with start_screen:
        gr.Markdown("# Kepptu við risamállíkönin!")
        gr.Markdown(
            "Veldu þér einn af flokkunum að neðan og þreyttu stutta útgáfu af prófi sem við leggjum fyrir risamállíkönin. "
            "Eftir að þú hefur lokið prófinu færðu að sjá hvar þú stendur miðað við líkönin."
        )
        benchmark_buttons = {
            name: gr.Button(info["name"]) for name, info in BENCHMARKS.items()
        }

    quiz_screen = gr.Column(visible=False)
    with quiz_screen:
        question_number = gr.Markdown()
        question_text = gr.Markdown()
        answer_input = gr.Radio(choices=[], visible=False)
        free_text_input = gr.Textbox(visible=False)
        with gr.Row():
            previous_button = gr.Button("Fyrri")
            next_button = gr.Button("Næsta")

    score_screen = gr.Column(visible=False)
    with score_screen:
        gr.Markdown(f"## Niðurstöður")
        score_plot = gr.Plot()
        reset_btn = gr.Button("Byrja upp á nýtt")
        results_container = gr.Column(visible=False)
        with results_container:
            result_cards = [gr.Group(visible=False) for _ in range(5)]
            for card in result_cards:
                with card:
                    gr.Markdown("")

    quiz_state = gr.State()

    for benchmark_name, button in benchmark_buttons.items():
        button.click(
            fn=start_quiz_handler,
            inputs=[gr.State(benchmark_name)],
            outputs=[
                start_screen,
                quiz_screen,
                score_screen,
                question_number,
                question_text,
                answer_input,
                free_text_input,
                next_button,
                previous_button,
                quiz_state,
            ],
        )

    next_button.click(
        fn=next_question_handler,
        inputs=[quiz_state, answer_input, free_text_input],
        outputs=[
            quiz_screen,
            score_screen,
            question_number,
            question_text,
            answer_input,
            free_text_input,
            next_button,
            previous_button,
            score_plot,
            results_container,
            *result_cards,
            *[child for card in result_cards for child in card.children],
            quiz_state,
        ],
    )

    previous_button.click(
        fn=previous_question_handler,
        inputs=[quiz_state],
        outputs=[
            quiz_screen,
            question_number,
            question_text,
            answer_input,
            free_text_input,
            next_button,
            previous_button,
            quiz_state,
        ],
    )

    reset_btn.click(
        fn=reset_quiz_handler,
        inputs=[],
        outputs=[start_screen, quiz_screen, score_screen, next_button],
    )

demo.launch()