#!/usr/bin/env python3
"""ElementVerificationResult 値オブジェクトのテスト

正常系と異常系を含む包括的テスト。
"""

import pytest

from noveler.domain.value_objects.element_verification_result import ElementVerificationResult


class TestElementVerificationResult:
    """ElementVerificationResult 値オブジェクトのテストクラス"""

    # ========================================
    # 正常系テスト
    # ========================================

    def test_create_implemented_normal(self):
        """正常系: 完全実装結果の生成"""
        result = ElementVerificationResult.create_implemented(
            evidence="主人公は冒険者ギルドの扉を押し開けた。",
            confidence=0.95,
            reason="ギルド到着シーンが明確に描写されている",
            evidence_start=0,
            evidence_end=20,
        )

        assert result.status == "IMPLEMENTED"
        assert result.confidence == 0.95
        assert result.is_implemented()
        assert not result.is_partial()
        assert not result.is_missing()
        assert result.has_high_confidence()
        assert result.has_evidence()
        assert result.evidence_start == 0
        assert result.evidence_end == 20

    def test_create_partial_normal(self):
        """正常系: 部分実装結果の生成"""
        result = ElementVerificationResult.create_partial(
            reason="間接的な言及のみ",
            confidence=0.6,
            evidence="彼はそこに向かった。",
        )

        assert result.status == "PARTIAL"
        assert result.confidence == 0.6
        assert result.is_partial()
        assert not result.is_implemented()
        assert not result.has_high_confidence()

    def test_create_missing_normal(self):
        """正常系: 未実装結果の生成"""
        result = ElementVerificationResult.create_missing(
            reason="該当する描写が見当たらない",
            confidence=0.85,
        )

        assert result.status == "MISSING"
        assert result.confidence == 0.85
        assert result.is_missing()
        assert not result.has_evidence()
        assert result.evidence is None

    def test_to_dict_normal(self):
        """正常系: 辞書形式への変換"""
        result = ElementVerificationResult.create_implemented(
            evidence="test evidence",
            confidence=0.9,
            reason="test reason",
        )

        result_dict = result.to_dict()

        assert isinstance(result_dict, dict)
        assert result_dict["status"] == "IMPLEMENTED"
        assert result_dict["confidence"] == 0.9
        assert result_dict["reason"] == "test reason"
        assert result_dict["evidence"] == "test evidence"

    def test_high_confidence_threshold_custom(self):
        """正常系: カスタム閾値での高信頼度判定"""
        result = ElementVerificationResult.create_implemented(
            evidence="test",
            confidence=0.75,
            reason="test",
        )

        assert result.has_high_confidence(threshold=0.7)
        assert not result.has_high_confidence(threshold=0.8)

    def test_frozen_dataclass(self):
        """正常系: 不変性確認（frozenデータクラス）"""
        result = ElementVerificationResult.create_missing(reason="test", confidence=0.5)

        with pytest.raises(Exception):  # FrozenInstanceError or AttributeError
            result.status = "IMPLEMENTED"  # type: ignore

    # ========================================
    # 異常系テスト
    # ========================================

    def test_invalid_confidence_too_low(self):
        """異常系: 信頼度が範囲外（負数）"""
        with pytest.raises(ValueError, match="0.0-1.0の範囲"):
            ElementVerificationResult(
                status="IMPLEMENTED",
                confidence=-0.1,
                reason="test",
            )

    def test_invalid_confidence_too_high(self):
        """異常系: 信頼度が範囲外（1.0超過）"""
        with pytest.raises(ValueError, match="0.0-1.0の範囲"):
            ElementVerificationResult(
                status="PARTIAL",
                confidence=1.5,
                reason="test",
            )

    def test_invalid_status(self):
        """異常系: 無効なstatus値"""
        with pytest.raises(ValueError, match="IMPLEMENTED/PARTIAL/MISSING"):
            ElementVerificationResult(
                status="INVALID",  # type: ignore
                confidence=0.8,
                reason="test",
            )

    def test_invalid_evidence_range_reversed(self):
        """異常系: evidence_start > evidence_end"""
        with pytest.raises(ValueError, match="evidence_start.*evidence_end"):
            ElementVerificationResult(
                status="IMPLEMENTED",
                confidence=0.9,
                reason="test",
                evidence="test",
                evidence_start=100,
                evidence_end=50,  # start > end
            )

    def test_boundary_confidence_zero(self):
        """境界値テスト: confidence = 0.0"""
        result = ElementVerificationResult.create_missing(
            reason="完全に確信なし",
            confidence=0.0,
        )

        assert result.confidence == 0.0
        assert not result.has_high_confidence()

    def test_boundary_confidence_one(self):
        """境界値テスト: confidence = 1.0"""
        result = ElementVerificationResult.create_implemented(
            evidence="確実な証拠",
            confidence=1.0,
            reason="100%確実",
        )

        assert result.confidence == 1.0
        assert result.has_high_confidence()

    def test_empty_evidence_string(self):
        """境界値テスト: 空文字列のevidence"""
        result = ElementVerificationResult(
            status="PARTIAL",
            confidence=0.5,
            reason="test",
            evidence="",  # 空文字列
        )

        assert not result.has_evidence()  # 空文字列はevidenceなしと判定

    def test_whitespace_only_evidence(self):
        """境界値テスト: 空白のみのevidence"""
        result = ElementVerificationResult(
            status="PARTIAL",
            confidence=0.5,
            reason="test",
            evidence="   \n\t  ",  # 空白のみ
        )

        assert not result.has_evidence()  # 空白のみはevidenceなしと判定


@pytest.mark.spec("SPEC-PLOT-ADHERENCE-001")
class TestElementVerificationResultIntegration:
    """統合シナリオテスト"""

    def test_scenario_high_confidence_implemented(self):
        """シナリオ: 高信頼度の完全実装検証"""
        manuscript = "主人公の太郎は冒険者ギルドの受付で初めての依頼を受け取った。彼は緊張しながらも前に進んだ。"

        result = ElementVerificationResult.create_implemented(
            evidence="主人公の太郎は冒険者ギルドの受付で初めての依頼を受け取った。",
            confidence=0.92,
            reason="ギルド到着と依頼受注が明確に描写されている",
            evidence_start=0,
            evidence_end=len("主人公の太郎は冒険者ギルドの受付で初めての依頼を受け取った。"),
        )

        assert result.is_implemented()
        assert result.has_high_confidence()
        assert result.has_evidence()
        assert manuscript[result.evidence_start : result.evidence_end] == result.evidence

    def test_scenario_low_confidence_partial(self):
        """シナリオ: 低信頼度の部分実装検証"""
        result = ElementVerificationResult.create_partial(
            reason="間接的な言及のみで詳細描写なし",
            confidence=0.45,
            evidence="彼はそこへ向かった。",
        )

        assert result.is_partial()
        assert not result.has_high_confidence()
        assert not result.has_high_confidence(threshold=0.5)

    def test_scenario_missing_no_evidence(self):
        """シナリオ: 未実装（エビデンスなし）"""
        result = ElementVerificationResult.create_missing(
            reason="プロット要素に関する記述が全く見当たらない",
            confidence=0.88,
        )

        assert result.is_missing()
        assert result.has_high_confidence()  # 高信頼度で「ない」と判定
        assert not result.has_evidence()
