"""core/types.py 单元测试。"""

from __future__ import annotations

from pathlib import Path

import pytest

from core.types import GeneratedQuestion, LLMResponse, PoolConfig


class TestLLMResponse:
    @pytest.fixture()
    def sample_response(self) -> LLMResponse:
        return LLMResponse(
            content="回答内容",
            thinking="思考过程",
            model="deepseek-v4-pro",
            provider="deepseek",
            prompt_tokens=100,
            completion_tokens=50,
            latency_ms=1200,
            ttft_ms=350.0,
            max_inter_token_ms=45.0,
            cache_hit=False,
            call_id="test-uuid-001",
        )

    def test_frozen_prevents_mutation(self, sample_response: LLMResponse) -> None:
        with pytest.raises(AttributeError):
            sample_response.content = "篡改"

    def test_all_fields_accessible(self, sample_response: LLMResponse) -> None:
        assert sample_response.content == "回答内容"
        assert sample_response.thinking == "思考过程"
        assert sample_response.model == "deepseek-v4-pro"
        assert sample_response.provider == "deepseek"
        assert sample_response.prompt_tokens == 100
        assert sample_response.completion_tokens == 50
        assert sample_response.latency_ms == 1200
        assert sample_response.ttft_ms == 350.0
        assert sample_response.max_inter_token_ms == 45.0
        assert sample_response.cache_hit is False
        assert sample_response.call_id == "test-uuid-001"

    def test_cache_hit_response_has_none_ttft(self) -> None:
        resp = LLMResponse(
            content="cached",
            thinking="",
            model="m",
            provider="p",
            prompt_tokens=0,
            completion_tokens=0,
            latency_ms=1,
            ttft_ms=None,
            max_inter_token_ms=None,
            cache_hit=True,
            call_id="c",
        )
        assert resp.ttft_ms is None
        assert resp.max_inter_token_ms is None
        assert resp.cache_hit is True


class TestGeneratedQuestion:
    @pytest.fixture()
    def sample_question(self) -> GeneratedQuestion:
        return GeneratedQuestion(
            question_id="719-1",
            video_id="B7Hh0PY1kks",
            task_type="Action Reasoning",
            question="What are the differing motivations?",
            options=("A. Option 1", "B. Option 2", "C. Option 3", "D. Option 4"),
            answer="B",
            source_nodes=(),
            difficulty="medium",
        )

    def test_frozen_prevents_mutation(self, sample_question: GeneratedQuestion) -> None:
        with pytest.raises(AttributeError):
            sample_question.question = "篡改"

    def test_all_fields_accessible(self, sample_question: GeneratedQuestion) -> None:
        assert sample_question.question_id == "719-1"
        assert sample_question.video_id == "B7Hh0PY1kks"
        assert sample_question.task_type == "Action Reasoning"
        assert sample_question.question == "What are the differing motivations?"
        assert sample_question.options == (
            "A. Option 1",
            "B. Option 2",
            "C. Option 3",
            "D. Option 4",
        )
        assert sample_question.answer == "B"
        assert sample_question.source_nodes == ()
        assert sample_question.difficulty == "medium"

    def test_options_is_tuple(self, sample_question: GeneratedQuestion) -> None:
        assert isinstance(sample_question.options, tuple)

    def test_source_nodes_is_tuple(self, sample_question: GeneratedQuestion) -> None:
        assert isinstance(sample_question.source_nodes, tuple)


class TestPoolConfig:
    """PoolConfig frozen dataclass 基本行为。"""

    def test_pool_config_frozen(self) -> None:
        """PoolConfig 创建后不可变。"""
        cfg = PoolConfig(
            task_types=("Action Reasoning",),
            seed=42,
            baseline_run_id="baseline_v2",
            diag_size=200,
            diag_correct_ratio=0.5,
            val_size=30,
            val_correct_ratio=0.5,
            test_size=60,
            eval_min_per_class=2,
            train_ratio=0.667,
            test_questions_dir=Path("store/questions/benchmarks/Video-MME"),
        )
        assert cfg.task_types == ("Action Reasoning",)
        assert cfg.baseline_run_id == "baseline_v2"
        assert cfg.train_ratio == 0.667
        with pytest.raises(AttributeError):
            cfg.seed = 1

    def test_pool_config_task_types_none(self) -> None:
        """task_types=None 表示全部类别。"""
        cfg = PoolConfig(
            task_types=None,
            seed=0,
            baseline_run_id="run_1",
            diag_size=200,
            diag_correct_ratio=0.5,
            val_size=30,
            val_correct_ratio=0.5,
            test_size=60,
            eval_min_per_class=2,
            train_ratio=0.667,
            test_questions_dir=None,
        )
        assert cfg.task_types is None
        assert cfg.test_questions_dir is None
