"""Tests for quizbase_gui module."""

from __future__ import annotations

import json
from pathlib import Path

import pytest

from pytola.office.quizbase.quizbase import (
    MultipleChoiceQuestion,
    QuestionType,
)
from pytola.office.quizbase.quizbase_gui import (
    ConfigManager,
    QuizConfig,
)

try:
    from pytola.office.quizbase.quizbase_gui import QuestionAnswerWidget, QuizBaseMainWindow

    GUI_AVAILABLE = True
except ImportError:
    GUI_AVAILABLE = False

# Check if pytest-qt is available
import importlib.util

PYTEST_QT_AVAILABLE = importlib.util.find_spec("pytestqt") is not None


@pytest.fixture
def sample_quiz_json(tmp_path: Path) -> Path:
    """Create a sample quiz JSON file."""
    quiz_file = tmp_path / "quiz.json"
    quiz_data = {
        "questions": [
            {
                "question_id": "mc1",
                "question_type": "multiple_choice",
                "question_text": "What is 2+2?",
                "options": ["3", "4", "5", "6"],
                "correct_answer": 1,
                "allow_multiple": False,
                "points": 1.0,
            },
            {
                "question_id": "fb1",
                "question_type": "fill_blank",
                "question_text": "The capital of France is _____.",
                "correct_answers": ["Paris"],
                "case_sensitive": False,
                "points": 1.0,
            },
        ]
    }
    with open(quiz_file, "w", encoding="utf-8") as f:
        json.dump(quiz_data, f)
    return quiz_file


class TestConfigManager:
    """Tests for ConfigManager."""

    def test_default_config(self, tmp_path: Path):
        """Test loading default configuration."""
        config_file = tmp_path / "config.json"
        manager = ConfigManager(config_file)
        config = manager.get_config()

        assert isinstance(config, QuizConfig)
        assert config.window_width == 1000
        assert config.window_height == 700
        assert config.random_order is False

    def test_save_and_load(self, tmp_path: Path):
        """Test saving and loading configuration."""
        config_file = tmp_path / "config.json"
        manager = ConfigManager(config_file)

        # Modify config
        manager.set("window_width", 1200)
        manager.set("random_order", True)
        manager.save_config()

        # Load new instance
        manager2 = ConfigManager(config_file)
        config2 = manager2.get_config()

        assert config2.window_width == 1200
        assert config2.random_order is True

    def test_add_recent_file(self, tmp_path: Path):
        """Test adding recent file."""
        config_file = tmp_path / "config.json"
        manager = ConfigManager(config_file)

        # Add files
        manager.add_recent_file("quiz1.json")
        manager.add_recent_file("quiz2.json")
        manager.add_recent_file("quiz1.json")  # Duplicate

        config = manager.get_config()
        assert config.recent_files is not None
        assert len(config.recent_files) == 2
        assert config.recent_files[0] == "quiz1.json"
        assert config.recent_files[1] == "quiz2.json"

    def test_max_recent_files(self, tmp_path: Path):
        """Test maximum recent files limit."""
        config_file = tmp_path / "config.json"
        manager = ConfigManager(config_file)

        # Add more than MAX_RECENT_ITEMS
        for i in range(15):
            manager.add_recent_file(f"quiz{i}.json")

        config = manager.get_config()
        assert config.recent_files is not None
        assert len(config.recent_files) == ConfigManager.MAX_RECENT_ITEMS


@pytest.mark.skipif(
    not (GUI_AVAILABLE and PYTEST_QT_AVAILABLE),
    reason="PySide2 or pytest-qt not available",
)
class TestQuestionAnswerWidget:
    """Tests for QuestionAnswerWidget."""

    def test_set_multiple_choice_question(self, qtbot):
        """Test setting multiple choice question."""
        question = MultipleChoiceQuestion(
            question_id="mc1",
            question_type=QuestionType.MULTIPLE_CHOICE,
            question_text="What is 2+2?",
            options=["3", "4", "5", "6"],
            correct_answer=1,
            allow_multiple=False,
            points=1.0,
        )

        widget = QuestionAnswerWidget()
        qtbot.addWidget(widget)
        widget.show()
        widget.set_question(question)

        assert widget.question == question
        assert widget.current_answer_widget is not None

    def test_get_answer_radio(self, qtbot):
        """Test getting answer from radio buttons."""
        question = MultipleChoiceQuestion(
            question_id="mc1",
            question_type=QuestionType.MULTIPLE_CHOICE,
            question_text="What is 2+2?",
            options=["3", "4", "5", "6"],
            correct_answer=1,
            allow_multiple=False,
            points=1.0,
        )

        widget = QuestionAnswerWidget()
        qtbot.addWidget(widget)
        widget.show()
        widget.set_question(question)

        # No selection
        assert widget.get_answer() is None

        # Select second option
        widget.radio_buttons[1].setChecked(True)
        qtbot.wait(50)
        assert widget.get_answer() == 1

    def test_get_answer_checkbox(self, qtbot):
        """Test getting answer from checkboxes."""
        question = MultipleChoiceQuestion(
            question_id="mc1",
            question_type=QuestionType.MULTIPLE_CHOICE,
            question_text="Select primes",
            options=["2", "3", "4", "5"],
            correct_answer=[0, 1, 3],
            allow_multiple=True,
            points=1.0,
        )

        widget = QuestionAnswerWidget()
        qtbot.addWidget(widget)
        widget.show()
        widget.set_question(question)

        # Select first and last
        widget.checkboxes[0].setChecked(True)
        widget.checkboxes[3].setChecked(True)
        qtbot.wait(50)

        answer = widget.get_answer()
        assert isinstance(answer, list)
        assert 0 in answer
        assert 3 in answer

    def test_clear_answer(self, qtbot):
        """Test clearing answer."""
        question = MultipleChoiceQuestion(
            question_id="mc1",
            question_type=QuestionType.MULTIPLE_CHOICE,
            question_text="What is 2+2?",
            options=["3", "4", "5", "6"],
            correct_answer=1,
            allow_multiple=False,
            points=1.0,
        )

        widget = QuestionAnswerWidget()
        qtbot.addWidget(widget)
        widget.show()  # Ensure widget is visible
        widget.set_question(question)
        widget.radio_buttons[1].setChecked(True)

        # Process Qt events
        qtbot.wait(100)

        widget.clear_answer()

        # Process Qt events after clearing
        qtbot.wait(100)

        assert not widget.radio_buttons[1].isChecked()


@pytest.mark.skipif(
    not (GUI_AVAILABLE and PYTEST_QT_AVAILABLE),
    reason="PySide2 or pytest-qt not available",
)
class TestQuizBaseMainWindow:
    """Tests for QuizBaseMainWindow."""

    def test_window_creation(self, qtbot):
        """Test creating main window."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        assert window.windowTitle() == "QuizBase - Universal Quiz System"
        assert window.tab_widget.count() == 3  # Quiz, Summary, Wrong Answers

    def test_load_quiz(self, qtbot, sample_quiz_json: Path):
        """Test loading quiz file."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        window._load_quiz(str(sample_quiz_json))

        assert window.session is not None
        assert window.session.total_questions == 2
        assert window.submit_button.isEnabled()

    def test_create_sample_quiz(self, qtbot, tmp_path: Path, mocker):
        """Test creating sample quiz."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        sample_file = tmp_path / "sample.json"

        # Mock file dialog
        mocker.patch(
            "pytola.office.quizbase.quizbase_gui.QFileDialog.getSaveFileName",
            return_value=(str(sample_file), ""),
        )

        # Mock message box
        mocker.patch("pytola.office.quizbase.quizbase_gui.QMessageBox.information")

        window._create_sample_quiz()

        assert sample_file.exists()

    def test_submit_answer(self, qtbot, sample_quiz_json: Path):
        """Test submitting answer."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        window._load_quiz(str(sample_quiz_json))

        # Get answer widget and set answer
        answer_widget = window.answer_widget
        if hasattr(answer_widget, "radio_buttons"):
            answer_widget.radio_buttons[1].setChecked(True)

        window._submit_answer()

        assert window.current_result is not None
        assert window.session is not None
        assert len(window.session.results) == 1

    def test_progress_update(self, qtbot, sample_quiz_json: Path):
        """Test progress display update."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        window._load_quiz(str(sample_quiz_json))

        # Answer first question
        answer_widget = window.answer_widget
        if hasattr(answer_widget, "radio_buttons"):
            answer_widget.radio_buttons[1].setChecked(True)
        window._submit_answer()

        progress_text = window.progress_label.text()
        assert "Progress: 1 / 2" in progress_text

    def test_finish_quiz(self, qtbot, sample_quiz_json: Path, mocker):
        """Test finishing quiz."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        window._load_quiz(str(sample_quiz_json))

        # Answer all questions
        for _ in range(2):
            answer_widget = window.answer_widget
            if hasattr(answer_widget, "radio_buttons"):
                answer_widget.radio_buttons[1].setChecked(True)
            window._submit_answer()

        # Mock message box
        mocker.patch("pytola.office.quizbase.quizbase_gui.QMessageBox.information")

        window._finish_quiz()

        assert window.session is not None
        summary = window.session.get_summary()
        assert summary["answered"] == 2
        assert summary["is_finished"] is True

    def test_reset_quiz(self, qtbot, sample_quiz_json: Path, mocker):
        """Test resetting quiz."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        window._load_quiz(str(sample_quiz_json))

        # Answer a question
        answer_widget = window.answer_widget
        if hasattr(answer_widget, "radio_buttons"):
            answer_widget.radio_buttons[1].setChecked(True)
        window._submit_answer()

        # Mock confirmation dialog
        mocker.patch(
            "pytola.office.quizbase.quizbase_gui.QMessageBox.question",
            return_value=16384,  # QMessageBox.Yes
        )

        window._reset_quiz()

        assert window.session is not None
        assert len(window.session.results) == 0
        assert window.current_result is None

    def test_random_order_toggle(self, qtbot, sample_quiz_json: Path):
        """Test random order checkbox."""
        window = QuizBaseMainWindow()
        qtbot.addWidget(window)

        window._load_quiz(str(sample_quiz_json))

        # Toggle random order
        window.random_checkbox.setChecked(True)

        assert window.session is not None
        assert window.session.random_order is True
