"""ASR 自动字幕集成测试 — 验证渲染管道接入 ASR 的完整链路。"""

from __future__ import annotations

import tempfile
from dataclasses import dataclass
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest
from video_processing.unified_render_service import UnifiedRenderService

from packages.adapters.asr.mock_asr_service import MockASRService
from packages.domain.subtitle import SubtitleSegment, SubtitleTimeline

# ── Fixtures ──────────────────────────────────────────────────────────────────


@dataclass
class FakeClip:
    """模拟 EditPlanClip。"""

    id: str
    plan_id: str = "plan_001"
    asset_id: str = "asset_001"
    clip_type: str = "video"
    start_time: float = 0.0
    duration: float = 10.0
    layer: int = 0
    role: str = "main"
    config: dict = None


@dataclass
class FakePlan:
    """模拟 EditPlan。"""

    id: str = "plan_001"
    config: dict = None


@pytest.fixture
def work_dir():
    with tempfile.TemporaryDirectory() as tmpdir:
        yield Path(tmpdir)


@pytest.fixture
def test_video_path():
    """用 ffmpeg 生成一个5秒的测试视频（带音频）。"""
    import subprocess

    with tempfile.TemporaryDirectory() as tmpdir:
        video_path = Path(tmpdir) / "test.mp4"
        cmd = [
            "ffmpeg",
            "-y",
            "-f",
            "lavfi",
            "-i",
            "testsrc=duration=5:size=320x240:rate=30",
            "-f",
            "lavfi",
            "-i",
            "sine=frequency=440:duration=5",
            "-c:v",
            "libx264",
            "-preset",
            "ultrafast",
            "-c:a",
            "aac",
            "-shortest",
            str(video_path),
        ]
        result = subprocess.run(cmd, capture_output=True, timeout=30)
        if result.returncode != 0:
            pytest.skip(f"ffmpeg 不可用或生成测试视频失败: {result.stderr[:200]}")
        yield video_path


# ── 测试：ASR 服务接入 ────────────────────────────────────────────────────────


class TestASRServiceIntegration:
    def test_asr_service_in_init(self):
        """验证 asr_service 参数正确传递。"""
        plan = FakePlan(config={})
        service = UnifiedRenderService(
            plan=plan,
            clips=[],
            asset_path_map={},
            work_dir=Path("/tmp"),
            asr_service=MockASRService(),
        )
        assert service.asr_service is not None
        assert isinstance(service.asr_service, MockASRService)

    def test_no_asr_service_default(self):
        """验证不传 asr_service 时默认 None。"""
        plan = FakePlan(config={})
        service = UnifiedRenderService(
            plan=plan,
            clips=[],
            asset_path_map={},
            work_dir=Path("/tmp"),
        )
        assert service.asr_service is None

    def test_maybe_generate_ass_auto_subtitle_with_asr(self, work_dir, test_video_path):
        """验证 ASR 自动字幕模式：有 asr_service + auto_generated=true 时生成 ASS。"""
        plan = FakePlan(
            config={
                "subtitle": {
                    "enabled": True,
                    "auto_generated": True,
                    "position": "bottom",
                }
            }
        )
        clips = [
            FakeClip(id="clip_1", asset_id="asset_1", duration=5.0),
        ]
        asset_map = {"asset_1": test_video_path}

        service = UnifiedRenderService(
            plan=plan,
            clips=clips,
            asset_path_map=asset_map,
            work_dir=work_dir,
            output_width=320,
            output_height=240,
            asr_service=MockASRService(mock_text="这是ASR自动生成的测试字幕。用来验证渲染管道是否正常接入。"),
        )

        ass_path = service._maybe_generate_ass(5.0)

        assert ass_path is not None
        assert ass_path.exists()
        content = ass_path.read_text(encoding="utf-8")
        assert "[Events]" in content
        assert "Dialogue:" in content
        assert "ASR" in content

    def test_maybe_generate_ass_no_asr_service_skip_auto(self, work_dir):
        """验证没有 asr_service 时，即使 auto_generated=true 也不生成 ASR 字幕。"""
        plan = FakePlan(
            config={
                "subtitle": {
                    "enabled": True,
                    "auto_generated": True,
                    "text": "",
                }
            }
        )
        service = UnifiedRenderService(
            plan=plan,
            clips=[],
            asset_path_map={},
            work_dir=work_dir,
            asr_service=None,  # 没有 ASR 服务
        )

        ass_path = service._maybe_generate_ass(5.0)
        # 没有 ASR 服务 + 没有静态字幕文本 → 返回 None
        assert ass_path is None

    def test_maybe_generate_ass_auto_mode_ignores_text(self, work_dir):
        """验证 ASR 模式下即使有 text 字段也走 ASR（ASR无结果则无字幕）。"""
        plan = FakePlan(
            config={
                "subtitle": {
                    "enabled": True,
                    "auto_generated": True,
                    "text": "静态字幕文本",  # ASR模式下忽略此字段
                }
            }
        )
        mock_asr = MockASRService()
        mock_asr.transcribe = MagicMock(side_effect=mock_asr.transcribe)

        service = UnifiedRenderService(
            plan=plan,
            clips=[],
            asset_path_map={},
            work_dir=work_dir,
            asr_service=mock_asr,
        )

        ass_path = service._maybe_generate_ass(5.0)
        # ASR模式下无素材 → 无结果 → 返回None（不fallback到静态text）
        assert ass_path is None

    def test_maybe_generate_ass_title_still_works(self, work_dir):
        """验证 ASR 模式下不影响 title 的处理（两者独立）。"""
        plan = FakePlan(
            config={
                "title": {
                    "enabled": True,
                    "text": "视频标题",
                    "position": "top",
                },
                "subtitle": {
                    "enabled": False,  # 字幕关闭
                    "auto_generated": True,
                },
            }
        )
        mock_asr = MockASRService()

        service = UnifiedRenderService(
            plan=plan,
            clips=[],
            asset_path_map={},
            work_dir=work_dir,
            asr_service=mock_asr,
        )

        ass_path = service._maybe_generate_ass(5.0)
        assert ass_path is not None
        content = ass_path.read_text(encoding="utf-8")
        assert "视频标题" in content

    def test_asr_failure_does_not_block(self, work_dir, test_video_path):
        """验证 ASR 失败时不阻断主流程，降级为无字幕。"""
        plan = FakePlan(
            config={
                "subtitle": {
                    "enabled": True,
                    "auto_generated": True,
                }
            }
        )
        clips = [FakeClip(id="clip_1", asset_id="asset_1", duration=5.0)]
        asset_map = {"asset_1": test_video_path}

        # ASR 服务总是抛异常
        bad_asr = MockASRService()
        bad_asr.transcribe = MagicMock(side_effect=RuntimeError("ASR service down"))

        service = UnifiedRenderService(
            plan=plan,
            clips=clips,
            asset_path_map=asset_map,
            work_dir=work_dir,
            output_width=320,
            output_height=240,
            asr_service=bad_asr,
        )

        # 应该不抛异常，返回 None（降级）
        ass_path = service._maybe_generate_ass(5.0)
        assert ass_path is None  # ASR 失败 → 无字幕

    def test_auto_subtitle_disabled(self, work_dir):
        """验证 subtitle.enabled=false 时即使 auto_generated=true 也不生成。"""
        plan = FakePlan(
            config={
                "subtitle": {
                    "enabled": False,
                    "auto_generated": True,
                }
            }
        )
        mock_asr = MockASRService()
        mock_asr.transcribe = MagicMock()

        service = UnifiedRenderService(
            plan=plan,
            clips=[],
            asset_path_map={},
            work_dir=work_dir,
            asr_service=mock_asr,
        )

        ass_path = service._maybe_generate_ass(5.0)
        assert ass_path is None
        mock_asr.transcribe.assert_not_called()


# ── 测试：SubtitleConfig 扩展 ────────────────────────────────────────────────


class TestSubtitleConfigExtension:
    def test_config_has_auto_generated_field(self):
        """验证 SubtitleConfig 有 auto_generated 字段。"""
        from packages.domain.config_schemas import SubtitleConfig

        config = SubtitleConfig()
        assert hasattr(config, "auto_generated")
        assert config.auto_generated is False  # 默认关闭

    def test_config_default_values(self):
        """验证新增字段的默认值。"""
        from packages.domain.config_schemas import SubtitleConfig

        config = SubtitleConfig()
        assert config.auto_generated is False
        assert config.language == ""
        assert config.max_chars_per_line == 20
        assert config.min_chars_per_segment == 8

    def test_config_custom_values(self):
        """验证可以自定义 ASR 相关字段。"""
        from packages.domain.config_schemas import SubtitleConfig

        config = SubtitleConfig(
            auto_generated=True,
            language="zh",
            max_chars_per_line=15,
            min_chars_per_segment=5,
        )
        assert config.auto_generated is True
        assert config.language == "zh"
        assert config.max_chars_per_line == 15
        assert config.min_chars_per_segment == 5

    def test_config_validation_max_chars(self):
        """验证 max_chars_per_line 的范围校验。"""
        from pydantic import ValidationError

        from packages.domain.config_schemas import SubtitleConfig

        with pytest.raises(ValidationError):
            SubtitleConfig(max_chars_per_line=5)  # 小于8

        with pytest.raises(ValidationError):
            SubtitleConfig(max_chars_per_line=50)  # 大于40
