"""QuizTrainer 核心业务逻辑."""

from __future__ import annotations

import json
import random
import uuid
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from .models import (
    AnswerRecord,
    BaseQuestion,
    ChoiceQuestion,
    Difficulty,
    EssayQuestion,
    FillQuestion,
    QuestionType,
    QuizCategory,
    TrueFalseQuestion,
    UserData,
)


class DataManager:
    """数据管理器,负责题库和用户数据的读写."""

    DATA_DIR = Path.home() / ".quiztrainer"
    QUESTIONS_DIR = DATA_DIR / "questions"
    USER_DATA_DIR = DATA_DIR / "user_data"

    def __init__(self) -> None:
        """初始化数据管理器."""
        self._ensure_directories()

    def _ensure_directories(self) -> None:
        """确保数据目录存在."""
        self.DATA_DIR.mkdir(parents=True, exist_ok=True)
        self.QUESTIONS_DIR.mkdir(parents=True, exist_ok=True)
        self.USER_DATA_DIR.mkdir(parents=True, exist_ok=True)

    def _load_json(self, file_path: Path) -> dict[str, Any] | list[dict[str, Any]]:
        """加载 JSON 文件."""
        if not file_path.exists():
            return {} if file_path.suffix == ".json" else []
        try:
            with Path(file_path).open("r", encoding="utf-8") as f:
                return json.load(f)
        except (OSError, json.JSONDecodeError):
            return {} if file_path.suffix == ".json" else []

    def _save_json(self, file_path: Path, data: object) -> None:
        """保存 JSON 文件."""
        with Path(file_path).open("w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

    def load_question_bank(self, bank_name: str | None = None) -> list[BaseQuestion]:
        """加载题库.

        Parameters
        ----------
        bank_name : str | None
            题库名称, None 时加载所有题库

        Returns
        -------
        list[BaseQuestion]
            题目列表
        """
        questions: list[BaseQuestion] = []

        banks = [bank_name] if bank_name else [f.stem for f in self.QUESTIONS_DIR.glob("*.json")]

        for bank in banks:
            file_path = self.QUESTIONS_DIR / f"{bank}.json"
            data = self._load_json(file_path)
            if isinstance(data, list):
                for q_data in data:
                    q_data["_bank"] = bank
                    questions.append(BaseQuestion.from_dict(q_data))

        return questions

    def save_question_bank(
        self,
        bank_name: str,
        questions: list[BaseQuestion],
    ) -> None:
        """保存题库.

        Parameters
        ----------
        bank_name : str
            题库名称
        questions : list[BaseQuestion]
            题目列表
        """
        file_path = self.QUESTIONS_DIR / f"{bank_name}.json"
        data = [q.to_dict() for q in questions]
        self._save_json(file_path, data)

    def get_categories(self) -> list[QuizCategory]:
        """获取所有题目分类.

        Returns
        -------
        list[QuizCategory]
            分类列表
        """
        categories: dict[str, dict[str, Any]] = {}
        questions = self.load_question_bank()

        for q in questions:
            if q.category not in categories:
                categories[q.category] = {
                    "name": q.category,
                    "description": "",
                    "questions": [],
                    "difficulty_dist": {"easy": 0, "medium": 0, "hard": 0},
                }
            categories[q.category]["questions"].append(q)
            categories[q.category]["difficulty_dist"][q.difficulty.value] += 1

        return [
            QuizCategory(
                name=cat_data["name"],
                description=cat_data["description"],
                question_count=len(cat_data["questions"]),
                difficulty_dist=cat_data["difficulty_dist"],
            )
            for cat_data in categories.values()
        ]

    def load_user_data(self, user_id: str = "default") -> UserData:
        """加载用户数据.

        Parameters
        ----------
        user_id : str
            用户ID

        Returns
        -------
        UserData
            用户数据
        """
        file_path = self.USER_DATA_DIR / f"{user_id}.json"
        data = self._load_json(file_path)
        return UserData.from_dict(data) if data else UserData(user_id=user_id)

    def save_user_data(self, user_data: UserData) -> None:
        """保存用户数据.

        Parameters
        ----------
        user_data : UserData
            用户数据
        """
        file_path = self.USER_DATA_DIR / f"{user_data.user_id}.json"
        self._save_json(file_path, user_data.to_dict())

    def add_question(self, question: BaseQuestion, bank_name: str) -> None:
        """添加题目到题库.

        Parameters
        ----------
        question : BaseQuestion
            题目
        bank_name : str
            题库名称
        """
        questions = self.load_question_bank(bank_name)
        questions.append(question)
        self.save_question_bank(bank_name, questions)

    def delete_question(self, question_id: str, bank_name: str) -> bool:
        """删除题目.

        Parameters
        ----------
        question_id : str
            题目ID
        bank_name : str
            题库名称

        Returns
        -------
        bool
            是否成功删除
        """
        questions = self.load_question_bank(bank_name)
        original_count = len(questions)
        questions = [q for q in questions if q.id != question_id]
        if len(questions) < original_count:
            self.save_question_bank(bank_name, questions)
            return True
        return False

    def get_question_banks(self) -> list[str]:
        """获取所有题库名称.

        Returns
        -------
        list[str]
            题库名称列表
        """
        return [f.stem for f in self.QUESTIONS_DIR.glob("*.json")]


class QuizSession:
    """答题会话,管理一次答题过程."""

    def __init__(
        self,
        questions: list[BaseQuestion],
        mode: str = "practice",
        user_id: str = "default",
        data_manager: DataManager | None = None,
    ) -> None:
        """初始化答题会话.

        Parameters
        ----------
        questions : list[BaseQuestion]
            题目列表
        mode : str
            答题模式: practice | exam
        user_id : str
            用户ID
        data_manager : DataManager | None
            数据管理器
        """
        self.questions = questions
        self.mode = mode
        self.user_id = user_id
        self.data_manager = data_manager or DataManager()
        self.current_index = 0
        self.answers: list[AnswerRecord] = []
        self.start_time = datetime.now(tz=timezone.utc)
        self._session_id = str(uuid.uuid4())

    @property
    def current_question(self) -> BaseQuestion | None:
        """当前题目."""
        if 0 <= self.current_index < len(self.questions):
            return self.questions[self.current_index]
        return None

    @property
    def progress(self) -> dict[str, int]:
        """答题进度."""
        return {
            "current": self.current_index + 1,
            "total": len(self.questions),
            "answered": len(self.answers),
        }

    @property
    def is_complete(self) -> bool:
        """是否完成所有题目."""
        return self.current_index >= len(self.questions)

    def submit_answer(self, user_answer: str | bool) -> AnswerRecord:  # noqa: FBT001
        """提交答案.

        Parameters
        ----------
        user_answer : str | bool
            用户答案

        Returns
        -------
        AnswerRecord
            答题记录
        """
        if not self.current_question:
            msg = "没有当前题目"
            raise ValueError(msg)

        question = self.current_question
        is_correct = question.check_answer(user_answer=user_answer)

        record = AnswerRecord(
            question_id=question.id,
            user_answer=user_answer,
            is_correct=is_correct,
            timestamp=datetime.now(tz=timezone.utc).isoformat(),
        )
        self.answers.append(record)

        # 更新用户数据
        if self.mode == "practice":
            self._update_user_data(record, question)

        return record

    def _update_user_data(self, record: AnswerRecord, question: BaseQuestion) -> None:
        """更新用户数据."""
        user_data = self.data_manager.load_user_data(self.user_id)
        user_data.history.append(record)

        # 更新分类统计
        if question.category not in user_data.category_stats:
            user_data.category_stats[question.category] = {"total": 0, "correct": 0}
        stats = user_data.category_stats[question.category]
        stats["total"] += 1
        if record.is_correct:
            stats["correct"] += 1

        self.data_manager.save_user_data(user_data)

    def next_question(self) -> BaseQuestion | None:
        """移动到下一题."""
        if self.current_index < len(self.questions) - 1:
            self.current_index += 1
            return self.current_question
        return None

    def prev_question(self) -> BaseQuestion | None:
        """移动到上一题."""
        if self.current_index > 0:
            self.current_index -= 1
            return self.current_question
        return None

    def jump_to(self, index: int) -> BaseQuestion | None:
        """跳转到指定题目.

        Parameters
        ----------
        index : int
            题目索引

        Returns
        -------
        BaseQuestion | None
            目标题目
        """
        if 0 <= index < len(self.questions):
            self.current_index = index
            return self.current_question
        return None

    def get_results(self) -> dict[str, Any]:
        """获取答题结果.

        Returns
        -------
        dict[str, Any]
            结果数据
        """
        total_answered = len(self.answers)
        correct = sum(1 for a in self.answers if a.is_correct)
        accuracy = round(correct / total_answered * 100, 1) if total_answered > 0 else 0

        # 按分类统计
        category_stats: dict[str, dict[str, int]] = {}
        for i, record in enumerate(self.answers):
            if i < len(self.questions):
                cat = self.questions[i].category
                if cat not in category_stats:
                    category_stats[cat] = {"total": 0, "correct": 0}
                category_stats[cat]["total"] += 1
                if record.is_correct:
                    category_stats[cat]["correct"] += 1

        # 错题列表
        wrong_questions = [
            {
                "question": self.questions[i],
                "user_answer": a.user_answer,
                "record": a,
            }
            for i, a in enumerate(self.answers)
            if not a.is_correct
        ]

        return {
            "session_id": self._session_id,
            "total": len(self.questions),  # 总题数
            "total_answered": total_answered,  # 已答题数
            "correct": correct,  # 答对题数
            "wrong": total_answered - correct,  # 答错题数
            "accuracy": accuracy,  # 正确率
            "category_stats": category_stats,
            "wrong_questions": wrong_questions,
            "answers": self.answers,
            "start_time": self.start_time.isoformat(),
            "end_time": datetime.now(tz=timezone.utc).isoformat(),
        }

    def shuffle(self) -> None:
        """打乱题目顺序."""
        random.shuffle(self.questions)


class QuizManager:
    """题库管理器,提供便捷的题库操作接口."""

    def __init__(self, data_manager: DataManager | None = None) -> None:
        """初始化题库管理器."""
        self.data_manager = data_manager or DataManager()

    def create_question(
        self,
        q_type: str,
        question: str,
        *,
        answer: str | bool | list,
        category: str = "默认分类",
        difficulty: str = "medium",
        explanation: str = "",
        options: list[str] | None = None,
    ) -> BaseQuestion:
        """创建题目.

        Parameters
        ----------
        q_type : str
            题目类型
        question : str
            题目内容
        answer : str | bool | list
            正确答案
        category : str
            分类
        difficulty : str
            难度
        explanation : str
            解析
        options : list[str] | None
            选项(选择题用)

        Returns
        -------
        BaseQuestion
            创建的题目
        """
        q_id = str(uuid.uuid4())[:8]
        q_type_enum = QuestionType(q_type)
        difficulty_enum = Difficulty(difficulty)

        base_data = {
            "id": q_id,
            "type": q_type_enum.value,
            "category": category,
            "difficulty": difficulty_enum.value,
            "question": question,
            "answer": answer,
            "explanation": explanation,
        }

        if q_type_enum == QuestionType.CHOICE and options:
            base_data["options"] = options
            return ChoiceQuestion.from_dict(base_data)
        if q_type_enum == QuestionType.TRUEFALSE:
            return TrueFalseQuestion.from_dict(base_data)
        if q_type_enum == QuestionType.FILL:
            return FillQuestion.from_dict(base_data)
        if q_type_enum == QuestionType.ESSAY:
            return EssayQuestion.from_dict(base_data)
        return BaseQuestion.from_dict(base_data)

    def filter_questions(
        self,
        bank_name: str | None = None,
        q_type: str | None = None,
        category: str | None = None,
        difficulty: str | None = None,
        limit: int | None = None,
    ) -> list[BaseQuestion]:
        """筛选题目.

        Parameters
        ----------
        bank_name : str | None
            题库名称
        q_type : str | None
            题目类型
        category : str | None
            分类
        difficulty : str | None
            难度
        limit : int | None
            限制数量

        Returns
        -------
        list[BaseQuestion]
            筛选后的题目列表
        """
        questions = self.data_manager.load_question_bank(bank_name)

        if q_type:
            questions = [q for q in questions if q.type.value == q_type]
        if category:
            questions = [q for q in questions if q.category == category]
        if difficulty:
            questions = [q for q in questions if q.difficulty.value == difficulty]

        if limit:
            questions = random.sample(questions, min(limit, len(questions)))

        return questions

    def start_quiz(
        self,
        bank_name: str | None = None,
        q_type: str | None = None,
        category: str | None = None,
        difficulty: str | None = None,
        count: int = 10,
        mode: str = "practice",
        *,
        shuffle: bool = True,
        user_id: str = "default",
    ) -> QuizSession:
        """开始答题.

        Parameters
        ----------
        bank_name : str | None
            题库名称
        q_type : str | None
            题目类型
        category : str | None
            分类
        difficulty : str | None
            难度
        count : int
            题目数量
        mode : str
            答题模式
        shuffle : bool
            是否打乱
        user_id : str
            用户ID

        Returns
        -------
        QuizSession
            答题会话
        """
        questions = self.filter_questions(
            bank_name=bank_name,
            q_type=q_type,
            category=category,
            difficulty=difficulty,
            limit=count,
        )

        if shuffle:
            random.shuffle(questions)

        return QuizSession(
            questions=questions,
            mode=mode,
            user_id=user_id,
            data_manager=self.data_manager,
        )

    def get_statistics(self, user_id: str = "default") -> dict[str, Any]:
        """获取用户统计信息.

        Parameters
        ----------
        user_id : str
            用户ID

        Returns
        -------
        dict[str, Any]
            统计信息
        """
        user_data = self.data_manager.load_user_data(user_id)

        # 基础统计
        stats = {
            "total_questions": user_data.total_questions,
            "correct_count": user_data.correct_count,
            "accuracy": user_data.accuracy,
            "category_stats": user_data.category_stats,
        }

        # 难度统计
        all_questions = self.data_manager.load_question_bank()
        difficulty_stats: dict[str, dict[str, int]] = {}
        for q in all_questions:
            if q.difficulty.value not in difficulty_stats:
                difficulty_stats[q.difficulty.value] = {"total": 0, "correct": 0}
            # 这里简化处理,实际应该从历史记录中获取
            difficulty_stats[q.difficulty.value]["total"] += 1

        stats["difficulty_stats"] = difficulty_stats

        # 最近答题记录
        recent_history = user_data.history[-20:] if user_data.history else []
        stats["recent_history"] = [r.to_dict() for r in recent_history]

        return stats
