# File: tests/integration/ai_integration/test_plot_analysis_integration.py
# Purpose: Validate plot analysis workflows end-to-end using real repositories and services.
# Context: Exercises AnalyzePlotUseCase with concrete YAML inputs and JSON outputs under pytest-managed temp dirs.

"""Integration tests for the plot analysis workflow."""

from pathlib import Path

import pytest
import yaml
from pytest import TempPathFactory

from noveler.application.ai_integration.use_cases.analyze_plot_use_case import (
    AnalyzePlotUseCase,
    InvalidPlotFormatError,
    PlotFileNotFoundError,
)
from noveler.domain.ai_integration.services.plot_analysis_service import PlotAnalysisService
from noveler.infrastructure.ai_integration.repositories.json_analysis_repository import JsonAnalysisRepository
from noveler.infrastructure.ai_integration.repositories.yaml_plot_repository import YamlPlotRepository
from noveler.presentation.shared.shared_utilities import get_common_path_service


class TestPlotAnalysisIntegration:
    """Integration-level contract for plot analysis features."""

    @pytest.fixture(autouse=True)
    def _setup_environment(self, tmp_path_factory: TempPathFactory) -> None:
        """Provide a clean project root per test case."""
        self.project_root = Path(tmp_path_factory.mktemp("plot_analysis"))

        path_service = get_common_path_service()
        self.plot_dir = self.project_root / str(path_service.get_plots_dir()) / "章別プロット"
        self.plot_dir.mkdir(parents=True, exist_ok=True)

        self.analysis_dir = self.project_root / "logs" / "ai_analysis"
        self.analysis_dir.mkdir(parents=True, exist_ok=True)

        self.plot_repository = YamlPlotRepository(str(self.project_root))
        self.analysis_repository = JsonAnalysisRepository(str(self.analysis_dir))
        self.analysis_service = PlotAnalysisService()

        self.use_case = AnalyzePlotUseCase(
            plot_repository=self.plot_repository,
            analysis_repository=self.analysis_repository,
            analysis_service=self.analysis_service,
        )

    def _relative_plot_path(self, filename: str) -> str:
        return (self.plot_dir.relative_to(self.project_root) / filename).as_posix()

    def test_full_analysis_workflow(self) -> None:
        """End-to-end happy path for plot analysis."""
        plot_data = {
            "metadata": {"title": "ch01:始まりの時", "genre": "fantasy", "target_length": 10},
            "structure": {
                "setup": {"description": "平穏な日常の描写", "pages": "1-2"},
                "development": {"events": ["謎の訪問者", "運命の出会い", "最初の試練"]},
                "climax": {"description": "真実の発覚と決断", "emotional_peak": "驚きと決意"},
                "resolution": {"description": "新たな旅立ち", "next_chapter_hook": "未知の世界へ"},
            },
            "characters": {
                "protagonist": {
                    "name": "アレックス",
                    "motivation": "失われた記憶を取り戻す",
                    "arc": "無知から覚醒へ",
                    "conflicts": ["自己認識", "運命との対峙"],
                },
                "mentor": {"name": "賢者エルダー", "role": "導き手", "secret": "主人公の過去を知っている"},
            },
            "themes": {"main_theme": "自己発見の旅", "sub_themes": ["成長", "信頼", "犠牲"]},
        }

        plot_file = self.plot_dir / "chapter01.yaml"
        plot_file.write_text(yaml.dump(plot_data, allow_unicode=True), encoding="utf-8")

        plot_path = self._relative_plot_path("chapter01.yaml")
        analysis = self.use_case.execute(plot_path)

        assert analysis is not None
        assert analysis.plot_file_path == plot_path
        assert analysis.is_analyzed()
        assert analysis.result is not None

        result = analysis.result
        assert result.total_score.value >= 70
        assert len(result.strengths) > 0
        assert result.overall_advice != ""

        analysis_files = list(self.analysis_dir.glob("*.json"))
        assert len(analysis_files) == 1

    def test_analyze_nonexistent_file(self) -> None:
        with pytest.raises(PlotFileNotFoundError, match=".*"):
            self.use_case.execute("nonexistent.yaml")

    def test_analyze_minimal_plot(self) -> None:
        minimal_plot = {"structure": {"setup": {}, "development": {}, "climax": {}, "resolution": {}}}
        plot_file = self.plot_dir / "minimal.yaml"
        plot_file.write_text(yaml.dump(minimal_plot, allow_unicode=True), encoding="utf-8")

        analysis = self.use_case.execute(self._relative_plot_path("minimal.yaml"))

        assert analysis.is_analyzed()
        assert analysis.result.total_score.value < 70
        assert len(analysis.result.improvements) > 0

    def test_cache_functionality(self) -> None:
        plot_data = {"structure": {"setup": {"description": "test"}}}
        plot_file = self.plot_dir / "cache_test.yaml"
        plot_file.write_text(yaml.dump(plot_data, allow_unicode=True), encoding="utf-8")

        plot_path = self._relative_plot_path("cache_test.yaml")
        analysis1 = self.use_case.execute(plot_path)

        plot_data["structure"]["setup"]["description"] = "changed"
        plot_file.write_text(yaml.dump(plot_data, allow_unicode=True), encoding="utf-8")

        analysis2 = self.use_case.execute(plot_path, use_cache=True)

        assert analysis1.id == analysis2.id
        assert analysis1.result.total_score.value == analysis2.result.total_score.value

    def test_recent_analyses_retrieval(self) -> None:
        for i in range(3):
            plot_data = {"structure": {"setup": {"description": f"test{i}"}}}
            plot_file = self.plot_dir / f"test{i}.yaml"
            plot_file.write_text(yaml.dump(plot_data, allow_unicode=True), encoding="utf-8")
            self.use_case.execute(self._relative_plot_path(f"test{i}.yaml"))

        recent = self.use_case.get_recent_analyses(limit=2)

        assert len(recent) == 2
        assert recent[0].analyzed_at >= recent[1].analyzed_at

    def test_invalid_yaml_handling(self) -> None:
        invalid_file = self.plot_dir / "invalid.yaml"
        invalid_file.write_text("{ invalid yaml content :", encoding="utf-8")

        with pytest.raises(InvalidPlotFormatError, match=".*"):
            self.use_case.execute(self._relative_plot_path("invalid.yaml"))

    def test_japanese_content_handling(self) -> None:
        japanese_plot = {
            "metadata": {"title": "ch01:始まりの章", "genre": "ファンタジー"},
            "structure": {
                "setup": {"description": "静かな朝の描写"},
                "development": {"events": ["友人との再会", "不思議な予感", "冒険への決意"]},
                "climax": {"description": "真実との対峙"},
                "resolution": {"description": "新たな旅立ち"},
            },
            "characters": {"protagonist": {"name": "直人", "motivation": "真実の探索"}},
            "themes": {"main_theme": "友情と成長"},
        }

        plot_file = self.plot_dir / "japanese.yaml"
        plot_file.write_text(yaml.dump(japanese_plot, allow_unicode=True), encoding="utf-8")

        analysis = self.use_case.execute(self._relative_plot_path("japanese.yaml"))

        assert analysis.is_analyzed()
        assert analysis.result.total_score.value > 0
