"""ReverseEngine 单测 — 倒放引擎配置解析 + 滤镜构建."""

from __future__ import annotations

import pytest
from video_processing.reverse_engine import ReverseConfig, ReverseEngine

# ── ReverseConfig.from_dict ────────────────────────────────────────────────


class TestReverseConfigFromDict:
    """ReverseConfig.from_dict 配置解析."""

    def test_none_returns_disabled(self):
        config = ReverseConfig.from_dict(None)
        assert config.enabled is False
        assert config.reverse_video is True
        assert config.reverse_audio is True

    def test_empty_dict_returns_disabled(self):
        config = ReverseConfig.from_dict({})
        assert config.enabled is False

    def test_enabled_false(self):
        config = ReverseConfig.from_dict({"enabled": False})
        assert config.enabled is False

    def test_enabled_true_defaults(self):
        """只传 enabled=True，video/audio 默认都开."""
        config = ReverseConfig.from_dict({"enabled": True})
        assert config.enabled is True
        assert config.reverse_video is True
        assert config.reverse_audio is True

    def test_disable_video_only(self):
        config = ReverseConfig.from_dict(
            {
                "enabled": True,
                "reverse_video": False,
                "reverse_audio": True,
            }
        )
        assert config.enabled is True
        assert config.reverse_video is False
        assert config.reverse_audio is True

    def test_disable_audio_only(self):
        config = ReverseConfig.from_dict(
            {
                "enabled": True,
                "reverse_video": True,
                "reverse_audio": False,
            }
        )
        assert config.enabled is True
        assert config.reverse_video is True
        assert config.reverse_audio is False

    def test_both_disabled(self):
        config = ReverseConfig.from_dict(
            {
                "enabled": True,
                "reverse_video": False,
                "reverse_audio": False,
            }
        )
        assert config.enabled is True
        assert config.reverse_video is False
        assert config.reverse_audio is False

    def test_invalid_type_falls_back_default(self):
        """传入非字典类型（如列表），捕获 TypeError，返回默认配置."""
        config = ReverseConfig.from_dict([1, 2, 3])  # type: ignore[arg-type]
        assert config.enabled is False

    def test_attribute_error_falls_back(self):
        """没有 .get() 方法的对象，捕获 AttributeError，返回默认配置."""
        config = ReverseConfig.from_dict(123)  # type: ignore[arg-type]
        assert config.enabled is False

    def test_truthy_values(self):
        """非布尔真值也能被 bool() 转换."""
        config = ReverseConfig.from_dict(
            {
                "enabled": 1,
                "reverse_video": 1,
                "reverse_audio": "yes",
            }
        )
        assert config.enabled is True
        assert config.reverse_video is True
        assert config.reverse_audio is True

    def test_falsy_values(self):
        """非布尔假值也能被 bool() 转换."""
        config = ReverseConfig.from_dict(
            {
                "enabled": True,
                "reverse_video": 0,
                "reverse_audio": "",
            }
        )
        assert config.enabled is True
        assert config.reverse_video is False
        assert config.reverse_audio is False


# ── ReverseEngine.build_video_filter ───────────────────────────────────────


class TestBuildVideoFilter:
    """ReverseEngine.build_video_filter 视频倒放滤镜构建."""

    def test_disabled_returns_empty(self):
        config = ReverseConfig(enabled=False)
        result = ReverseEngine.build_video_filter(config)
        assert result == ""

    def test_enabled_but_video_off_returns_empty(self):
        config = ReverseConfig(enabled=True, reverse_video=False, reverse_audio=True)
        result = ReverseEngine.build_video_filter(config)
        assert result == ""

    def test_enabled_normal_duration(self):
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_video_filter(config, duration=10.0)
        assert result == "reverse"

    def test_zero_duration(self):
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_video_filter(config, duration=0.0)
        assert result == "reverse"

    def test_exactly_max_safe_duration(self):
        """刚好等于上限，允许."""
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_video_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION)
        assert result == "reverse"

    def test_exceeds_max_safe_duration_skips(self):
        """超过上限，跳过倒放，返回空字符串."""
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_video_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION + 1)
        assert result == ""

    def test_negative_duration(self):
        """负时长应该不会触发上限，但仍会正常返回 reverse."""
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_video_filter(config, duration=-5.0)
        assert result == "reverse"


# ── ReverseEngine.build_audio_filter ───────────────────────────────────────


class TestBuildAudioFilter:
    """ReverseEngine.build_audio_filter 音频倒放滤镜构建."""

    def test_disabled_returns_empty(self):
        config = ReverseConfig(enabled=False)
        result = ReverseEngine.build_audio_filter(config)
        assert result == ""

    def test_enabled_but_audio_off_returns_empty(self):
        config = ReverseConfig(enabled=True, reverse_video=True, reverse_audio=False)
        result = ReverseEngine.build_audio_filter(config)
        assert result == ""

    def test_enabled_normal_duration(self):
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_audio_filter(config, duration=10.0)
        assert result == "areverse"

    def test_zero_duration(self):
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_audio_filter(config, duration=0.0)
        assert result == "areverse"

    def test_exactly_max_safe_duration(self):
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_audio_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION)
        assert result == "areverse"

    def test_exceeds_max_safe_duration_skips(self):
        config = ReverseConfig(enabled=True)
        result = ReverseEngine.build_audio_filter(config, duration=ReverseEngine.MAX_SAFE_DURATION + 1)
        assert result == ""

    def test_both_video_and_audio_disabled(self):
        """两个都关，两个滤镜都为空."""
        config = ReverseConfig(enabled=True, reverse_video=False, reverse_audio=False)
        assert ReverseEngine.build_video_filter(config, 10) == ""
        assert ReverseEngine.build_audio_filter(config, 10) == ""
