"""TTS配音引擎纯逻辑测试 — 数据结构 + 边界情况（mock TTS服务）."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import MagicMock

import pytest
from video_processing.tts_engine import (
    TtsEngine,
    VoiceoverResult,
    VoiceoverSegment,
)

from packages.domain.tts_config import TtsConfig
from packages.ports.tts_service import TtsError


class TestVoiceoverSegment:
    """VoiceoverSegment 数据结构测试."""

    def test_default_values(self):
        """默认值正确."""
        seg = VoiceoverSegment(text="你好")
        assert seg.text == "你好"
        assert seg.start_time == 0.0
        assert seg.end_time == 0.0
        assert seg.audio_path is None
        assert seg.duration == 0.0

    def test_full_values(self):
        """完整字段."""
        seg = VoiceoverSegment(
            text="测试",
            start_time=1.5,
            end_time=3.5,
            audio_path=Path("/tmp/test.wav"),
            duration=2.0,
        )
        assert seg.text == "测试"
        assert seg.start_time == 1.5
        assert seg.end_time == 3.5
        assert seg.audio_path == Path("/tmp/test.wav")
        assert seg.duration == 2.0


class TestVoiceoverResult:
    """VoiceoverResult 数据结构测试."""

    def test_failure_default(self):
        """失败结果默认值."""
        result = VoiceoverResult(success=False)
        assert result.success is False
        assert result.segments == []
        assert result.total_duration == 0.0
        assert result.error_message == ""

    def test_success_with_segments(self):
        """成功结果带片段."""
        seg = VoiceoverSegment(text="hi", duration=5.0)
        result = VoiceoverResult(
            success=True,
            segments=[seg],
            total_duration=5.0,
        )
        assert result.success is True
        assert len(result.segments) == 1
        assert result.total_duration == 5.0

    def test_failure_with_message(self):
        """失败带错误信息."""
        result = VoiceoverResult(success=False, error_message="TTS出错")
        assert result.success is False
        assert result.error_message == "TTS出错"


class TestTtsEngineFullVoiceover:
    """TtsEngine.generate_full_voiceover 整段配音测试（mock TTS）."""

    def _make_engine(self, tmp_path: Path, tts: MagicMock | None = None) -> TtsEngine:
        """创建测试用TtsEngine."""
        if tts is None:
            tts = MagicMock()
            tts.synthesize.return_value = str(tmp_path / "out.wav")
        return TtsEngine(tts_service=tts, work_dir=tmp_path)

    def test_disabled_returns_failure(self, tmp_path):
        """配音未启用→失败."""
        engine = self._make_engine(tmp_path)
        config = TtsConfig(enabled=False, text="测试")
        result = engine.generate_full_voiceover(config)
        assert result.success is False
        assert "未启用" in result.error_message
        assert len(result.segments) == 0

    def test_empty_text_returns_failure(self, tmp_path):
        """文本为空→失败."""
        engine = self._make_engine(tmp_path)
        config = TtsConfig(enabled=True, text="   ")
        result = engine.generate_full_voiceover(config)
        assert result.success is False
        assert "文本为空" in result.error_message

    def test_success_creates_segment(self, tmp_path):
        """成功合成返回正确结构."""
        mock_tts = MagicMock()
        output_file = tmp_path / "voiceover_full.wav"
        output_file.write_bytes(b"fake audio")
        mock_tts.synthesize.return_value = str(output_file)

        engine = self._make_engine(tmp_path, mock_tts)
        config = TtsConfig(enabled=True, text="测试文本", voice_id="female_warm", speed=1.0)

        result = engine.generate_full_voiceover(config)

        assert result.success is True
        assert len(result.segments) == 1
        assert result.segments[0].text == "测试文本"
        assert result.segments[0].start_time == 0.0
        assert result.total_duration > 0
        mock_tts.synthesize.assert_called_once()

    def test_tts_error_returns_failure_gracefully(self, tmp_path):
        """TTS抛错→优雅降级返回失败."""
        mock_tts = MagicMock()
        mock_tts.synthesize.side_effect = TtsError("合成失败")

        engine = self._make_engine(tmp_path, mock_tts)
        config = TtsConfig(enabled=True, text="测试")

        result = engine.generate_full_voiceover(config)
        assert result.success is False
        assert "合成失败" in result.error_message

    def test_generic_exception_returns_failure(self, tmp_path):
        """其他异常也降级返回失败."""
        mock_tts = MagicMock()
        mock_tts.synthesize.side_effect = RuntimeError("未知错误")

        engine = self._make_engine(tmp_path, mock_tts)
        config = TtsConfig(enabled=True, text="测试")

        result = engine.generate_full_voiceover(config)
        assert result.success is False
        assert "未知错误" in result.error_message

    def test_work_dir_created(self, tmp_path):
        """工作目录自动创建."""
        new_dir = tmp_path / "nested" / "tts"
        mock_tts = MagicMock()
        TtsEngine(tts_service=mock_tts, work_dir=new_dir)
        assert new_dir.exists()


class TestTtsEngineSubtitleVoiceover:
    """TtsEngine.generate_subtitle_voiceover 字幕配音测试（mock TTS）."""

    def _make_engine(self, tmp_path: Path, tts: MagicMock | None = None) -> TtsEngine:
        if tts is None:
            tts = MagicMock()
        return TtsEngine(tts_service=tts, work_dir=tmp_path)

    def test_disabled_returns_failure(self, tmp_path):
        """配音未启用→失败."""
        engine = self._make_engine(tmp_path)
        config = TtsConfig(enabled=False, text="")
        result = engine.generate_subtitle_voiceover(config, [{"text": "hi", "start_time": 0, "end_time": 1}])
        assert result.success is False
        assert "未启用" in result.error_message

    def test_empty_subtitles_returns_failure(self, tmp_path):
        """字幕列表为空→失败."""
        engine = self._make_engine(tmp_path)
        config = TtsConfig(enabled=True, text="")
        result = engine.generate_subtitle_voiceover(config, [])
        assert result.success is False
        assert "字幕为空" in result.error_message

    def test_none_subtitles_returns_failure(self, tmp_path):
        """None字幕也失败."""
        engine = self._make_engine(tmp_path)
        config = TtsConfig(enabled=True, text="")
        result = engine.generate_subtitle_voiceover(config, None)  # type: ignore
        assert result.success is False
