"""Persian Language Tutor — Gradio UI."""

import json
import os
import tempfile
import time

import gradio as gr

import db
from modules import vocab, dashboard, essay, tutor, idioms
from modules.essay import GCSE_THEMES
from modules.tutor import THEME_PROMPTS
from anki_export import export_deck


# ---------- Initialise ----------
db.init_db()
vocabulary = vocab.load_vocab()
categories = ["All"] + vocab.get_categories()


# ---------- Helper ----------
def _rtl(text, size="2em"):
    return f'<div dir="rtl" style="font-size:{size}; text-align:center">{text}</div>'


# ================================================================
# TAB HANDLERS
# ================================================================

# ---------- Dashboard ----------
def refresh_dashboard():
    overview_md = dashboard.format_overview_markdown()
    cat_data = dashboard.get_category_breakdown()
    quiz_data = dashboard.get_recent_quizzes()
    return overview_md, cat_data, quiz_data


# ---------- Vocabulary Search ----------
def do_search(query, category):
    results = vocab.search(query)
    if category and category != "All":
        results = [r for r in results if r["category"] == category]
    if not results:
        return "No results found."
    lines = []
    for r in results:
        status = vocab.get_word_status(r["id"])
        icon = {"new": "⬜", "learning": "🟨", "mastered": "🟩"}.get(status, "⬜")
        lines.append(
            f'{icon} **{r["english"]}** — '
            f'<span dir="rtl">{r["persian"]}</span>'
            f' ({r.get("finglish", "")})'
        )
    return "\n\n".join(lines)


def do_random_word(category, transliteration):
    entry = vocab.get_random_word(category=category)
    if not entry:
        return "No words found."
    return vocab.format_word_card(entry, show_transliteration=transliteration)


# ---------- Flashcards ----------
def start_flashcards(category, direction):
    batch = vocab.get_flashcard_batch(count=10, category=category)
    if not batch:
        return "No words available.", [], 0, 0, "", gr.update(visible=False)

    first = batch[0]
    if direction == "English → Persian":
        prompt = f'<div style="font-size:2em; text-align:center">{first["english"]}</div>'
    else:
        prompt = _rtl(first["persian"])

    return (
        prompt,                    # card_display
        batch,                     # batch state
        0,                         # current index
        0,                         # score
        "",                        # answer_box cleared
        gr.update(visible=True),   # answer_area visible
    )


def submit_answer(user_answer, batch, index, score, direction, transliteration):
    if not batch or index >= len(batch):
        return "Session complete!", batch, index, score, "", gr.update(visible=False), ""

    entry = batch[index]
    dir_key = "en_to_fa" if direction == "English → Persian" else "fa_to_en"
    is_correct, correct_answer, _ = vocab.check_answer(entry["id"], user_answer, direction=dir_key)

    if is_correct:
        score += 1
        result = "✅ **Correct!**"
    else:
        result = f"❌ **Incorrect.** The answer is: "
        if dir_key == "en_to_fa":
            result += f'<span dir="rtl">{correct_answer}</span>'
        else:
            result += correct_answer

    card_info = vocab.format_word_card(entry, show_transliteration=transliteration)
    feedback = f"{result}\n\n{card_info}\n\n---\n*Rate your recall to continue:*"

    return feedback, batch, index, score, "", gr.update(visible=True), ""


def rate_and_next(rating_str, batch, index, score, direction):
    if not batch or index >= len(batch):
        return "Session complete!", batch, index, score, gr.update(visible=False)

    import fsrs as fsrs_mod
    rating_map = {
        "Again": fsrs_mod.Rating.Again,
        "Hard": fsrs_mod.Rating.Hard,
        "Good": fsrs_mod.Rating.Good,
        "Easy": fsrs_mod.Rating.Easy,
    }
    rating = rating_map.get(rating_str, fsrs_mod.Rating.Good)
    entry = batch[index]
    db.update_word_progress(entry["id"], rating)

    index += 1
    if index >= len(batch):
        summary = f"## Session Complete!\n\n**Score:** {score}/{len(batch)}\n\n"
        summary += f"**Accuracy:** {score/len(batch)*100:.0f}%"
        return summary, batch, index, score, gr.update(visible=False)

    next_entry = batch[index]
    if direction == "English → Persian":
        prompt = f'<div style="font-size:2em; text-align:center">{next_entry["english"]}</div>'
    else:
        prompt = _rtl(next_entry["persian"])

    return prompt, batch, index, score, gr.update(visible=True)


# ---------- Idioms ----------
def show_random_idiom(transliteration):
    expr = idioms.get_random_expression()
    return idioms.format_expression(expr, show_transliteration=transliteration), expr


def explain_idiom(expr_state):
    if not expr_state:
        return "Pick an idiom first."
    return idioms.explain_expression(expr_state)


def browse_idioms(transliteration):
    exprs = idioms.get_all_expressions()
    lines = []
    for e in exprs:
        line = f'**<span dir="rtl">{e["persian"]}</span>** — {e["english"]}'
        if transliteration != "off":
            line += f' *({e["finglish"]})*'
        lines.append(line)
    return "\n\n".join(lines)


# ---------- Tutor ----------
def start_tutor_lesson(theme):
    response, messages, system = tutor.start_lesson(theme)
    chat_history = [{"role": "assistant", "content": response}]
    return chat_history, messages, system, time.time()


def send_tutor_message(user_msg, chat_history, messages, system, audio_input):
    # Use STT if audio provided and no text
    if audio_input is not None and (not user_msg or not user_msg.strip()):
        try:
            from stt import transcribe_persian
            user_msg = transcribe_persian(audio_input)
        except Exception:
            user_msg = ""

    if not user_msg or not user_msg.strip():
        return chat_history, messages, "", None

    response, messages = tutor.process_response(user_msg, messages, system=system)
    chat_history.append({"role": "user", "content": user_msg})
    chat_history.append({"role": "assistant", "content": response})
    return chat_history, messages, "", None


def save_tutor(theme, messages, start_time):
    if messages and len(messages) > 1:
        tutor.save_session(theme, messages, start_time)
        return "Session saved!"
    return "Nothing to save."


# ---------- Essay ----------
def submit_essay(text, theme):
    if not text or not text.strip():
        return "Please write an essay first."
    return essay.mark_essay(text, theme)


def load_essay_history():
    return essay.get_essay_history()


# ---------- Settings / Export ----------
def do_anki_export(cats_selected):
    v = vocab.load_vocab()
    cats = cats_selected if cats_selected else None
    path = os.path.join(tempfile.gettempdir(), "gcse-persian.apkg")
    export_deck(v, categories=cats, output_path=path)
    return path


def reset_progress():
    conn = db.get_connection()
    conn.execute("DELETE FROM word_progress")
    conn.execute("DELETE FROM quiz_sessions")
    conn.execute("DELETE FROM essays")
    conn.execute("DELETE FROM tutor_sessions")
    conn.commit()
    return "Progress reset."


# ================================================================
# GRADIO UI
# ================================================================

with gr.Blocks(title="Persian Language Tutor") as app:
    gr.Markdown("# 🇮🇷 Persian Language Tutor\n*GCSE Persian vocabulary with spaced repetition*")

    # Shared state
    transliteration_state = gr.State(value="Finglish")

    with gr.Tabs():
        # ==================== DASHBOARD ====================
        with gr.Tab("📊 Dashboard"):
            overview_md = gr.Markdown("Loading...")
            with gr.Row():
                cat_table = gr.Dataframe(
                    headers=["Category", "Total", "Seen", "Mastered", "Progress"],
                    label="Category Breakdown",
                )
            quiz_table = gr.Dataframe(
                headers=["Date", "Category", "Score", "Duration"],
                label="Recent Quizzes",
            )
            refresh_btn = gr.Button("Refresh", variant="secondary")
            refresh_btn.click(
                fn=refresh_dashboard,
                outputs=[overview_md, cat_table, quiz_table],
            )

        # ==================== VOCABULARY ====================
        with gr.Tab("📚 Vocabulary"):
            with gr.Row():
                search_box = gr.Textbox(
                    label="Search (English or Persian)",
                    placeholder="Type to search...",
                )
                vocab_cat = gr.Dropdown(
                    choices=categories, value="All", label="Category"
                )
            search_btn = gr.Button("Search", variant="primary")
            random_btn = gr.Button("Random Word")
            search_results = gr.Markdown("Search for a word above.")

            search_btn.click(
                fn=do_search,
                inputs=[search_box, vocab_cat],
                outputs=[search_results],
            )
            search_box.submit(
                fn=do_search,
                inputs=[search_box, vocab_cat],
                outputs=[search_results],
            )
            random_btn.click(
                fn=do_random_word,
                inputs=[vocab_cat, transliteration_state],
                outputs=[search_results],
            )

        # ==================== FLASHCARDS ====================
        with gr.Tab("🃏 Flashcards"):
            with gr.Row():
                fc_category = gr.Dropdown(
                    choices=categories, value="All", label="Category"
                )
                fc_direction = gr.Radio(
                    ["English → Persian", "Persian → English"],
                    value="English → Persian",
                    label="Direction",
                )
            start_fc_btn = gr.Button("Start Session", variant="primary")

            card_display = gr.Markdown("Press 'Start Session' to begin.")

            # Hidden states
            fc_batch = gr.State([])
            fc_index = gr.State(0)
            fc_score = gr.State(0)

            with gr.Group(visible=False) as answer_area:
                answer_box = gr.Textbox(
                    label="Your answer",
                    placeholder="Type your answer...",
                    rtl=True,
                )
                submit_ans_btn = gr.Button("Submit Answer", variant="primary")
                answer_feedback = gr.Markdown("")

                with gr.Row():
                    btn_again = gr.Button("Again", variant="stop")
                    btn_hard = gr.Button("Hard", variant="secondary")
                    btn_good = gr.Button("Good", variant="primary")
                    btn_easy = gr.Button("Easy", variant="secondary")

            start_fc_btn.click(
                fn=start_flashcards,
                inputs=[fc_category, fc_direction],
                outputs=[card_display, fc_batch, fc_index, fc_score, answer_box, answer_area],
            )

            submit_ans_btn.click(
                fn=submit_answer,
                inputs=[answer_box, fc_batch, fc_index, fc_score, fc_direction, transliteration_state],
                outputs=[card_display, fc_batch, fc_index, fc_score, answer_box, answer_area, answer_feedback],
            )
            answer_box.submit(
                fn=submit_answer,
                inputs=[answer_box, fc_batch, fc_index, fc_score, fc_direction, transliteration_state],
                outputs=[card_display, fc_batch, fc_index, fc_score, answer_box, answer_area, answer_feedback],
            )

            for btn, label in [(btn_again, "Again"), (btn_hard, "Hard"), (btn_good, "Good"), (btn_easy, "Easy")]:
                btn.click(
                    fn=rate_and_next,
                    inputs=[gr.State(label), fc_batch, fc_index, fc_score, fc_direction],
                    outputs=[card_display, fc_batch, fc_index, fc_score, answer_area],
                )

        # ==================== IDIOMS ====================
        with gr.Tab("💬 Idioms & Expressions"):
            idiom_display = gr.Markdown("Click 'Random Idiom' or browse below.")
            idiom_state = gr.State(None)

            with gr.Row():
                random_idiom_btn = gr.Button("Random Idiom", variant="primary")
                explain_idiom_btn = gr.Button("Explain Usage")
                browse_idiom_btn = gr.Button("Browse All")

            idiom_explanation = gr.Markdown("")

            random_idiom_btn.click(
                fn=show_random_idiom,
                inputs=[transliteration_state],
                outputs=[idiom_display, idiom_state],
            )
            explain_idiom_btn.click(
                fn=explain_idiom,
                inputs=[idiom_state],
                outputs=[idiom_explanation],
            )
            browse_idiom_btn.click(
                fn=browse_idioms,
                inputs=[transliteration_state],
                outputs=[idiom_display],
            )

        # ==================== TUTOR ====================
        with gr.Tab("🎓 Tutor"):
            tutor_theme = gr.Dropdown(
                choices=list(THEME_PROMPTS.keys()),
                value="Identity and culture",
                label="Theme",
            )
            start_lesson_btn = gr.Button("New Lesson", variant="primary")

            chatbot = gr.Chatbot(label="Conversation")

            # Tutor states
            tutor_messages = gr.State([])
            tutor_system = gr.State("")
            tutor_start_time = gr.State(0)

            with gr.Row():
                tutor_input = gr.Textbox(
                    label="Your message",
                    placeholder="Type in English or Persian...",
                    scale=3,
                )
                tutor_mic = gr.Audio(
                    sources=["microphone"],
                    type="numpy",
                    label="Speak",
                    scale=1,
                )
            send_btn = gr.Button("Send", variant="primary")
            save_btn = gr.Button("Save Session", variant="secondary")
            save_status = gr.Markdown("")

            start_lesson_btn.click(
                fn=start_tutor_lesson,
                inputs=[tutor_theme],
                outputs=[chatbot, tutor_messages, tutor_system, tutor_start_time],
            )

            send_btn.click(
                fn=send_tutor_message,
                inputs=[tutor_input, chatbot, tutor_messages, tutor_system, tutor_mic],
                outputs=[chatbot, tutor_messages, tutor_input, tutor_mic],
            )
            tutor_input.submit(
                fn=send_tutor_message,
                inputs=[tutor_input, chatbot, tutor_messages, tutor_system, tutor_mic],
                outputs=[chatbot, tutor_messages, tutor_input, tutor_mic],
            )

            save_btn.click(
                fn=save_tutor,
                inputs=[tutor_theme, tutor_messages, tutor_start_time],
                outputs=[save_status],
            )

        # ==================== ESSAY ====================
        with gr.Tab("✍️ Essay"):
            essay_theme = gr.Dropdown(
                choices=GCSE_THEMES,
                value="Identity and culture",
                label="Theme",
            )
            essay_input = gr.Textbox(
                label="Write your essay in Persian",
                lines=10,
                rtl=True,
                placeholder="اینجا بنویسید...",
            )
            submit_essay_btn = gr.Button("Submit for Marking", variant="primary")
            essay_feedback = gr.Markdown("Write an essay and submit for AI marking.")

            gr.Markdown("### Essay History")
            essay_history_table = gr.Dataframe(
                headers=["Date", "Theme", "Grade", "Preview"],
                label="Past Essays",
            )
            refresh_essays_btn = gr.Button("Refresh History")

            submit_essay_btn.click(
                fn=submit_essay,
                inputs=[essay_input, essay_theme],
                outputs=[essay_feedback],
            )
            refresh_essays_btn.click(
                fn=load_essay_history,
                outputs=[essay_history_table],
            )

        # ==================== SETTINGS ====================
        with gr.Tab("⚙️ Settings"):
            gr.Markdown("## Settings")

            transliteration_radio = gr.Radio(
                ["off", "Finglish", "Academic"],
                value="Finglish",
                label="Transliteration",
            )

            ollama_model = gr.Textbox(
                label="Ollama Model",
                value="qwen2.5:7b",
                info="Model used for fast AI responses",
            )

            whisper_size = gr.Dropdown(
                choices=["tiny", "base", "small", "medium", "large-v3"],
                value="medium",
                label="Whisper Model Size",
            )

            gr.Markdown("### Anki Export")
            export_cats = gr.Dropdown(
                choices=vocab.get_categories(),
                multiselect=True,
                label="Categories to export (empty = all)",
            )
            export_btn = gr.Button("Export to Anki (.apkg)", variant="primary")
            export_file = gr.File(label="Download")

            export_btn.click(fn=do_anki_export, inputs=[export_cats], outputs=[export_file])

            gr.Markdown("### Reset")
            reset_btn = gr.Button("Reset All Progress", variant="stop")
            reset_status = gr.Markdown("")
            reset_btn.click(fn=reset_progress, outputs=[reset_status])

            # Wire transliteration state
            transliteration_radio.change(
                fn=lambda x: x,
                inputs=[transliteration_radio],
                outputs=[transliteration_state],
            )

    # Load dashboard on app start
    app.load(fn=refresh_dashboard, outputs=[overview_md, cat_table, quiz_table])


if __name__ == "__main__":
    app.launch(theme=gr.themes.Soft())
