"""filter_presets 模块单元测试."""

from dataclasses import FrozenInstanceError

import pytest
from domain.filter_presets import (
    FILTER_PRESET_LIBRARY,
    FilterPreset,
    build_ffmpeg_filter,
    get_filter_preset,
    list_filter_presets,
)


class TestFilterPreset:
    """FilterPreset 数据类测试."""

    def test_create_required_fields(self):
        f = FilterPreset(id="test_001", name="测试滤镜", category="basic")
        assert f.id == "test_001"
        assert f.name == "测试滤镜"
        assert f.category == "basic"
        # 默认值
        assert f.description == ""
        assert f.tags == []
        assert f.brightness == 0.0
        assert f.contrast == 1.0
        assert f.saturation == 1.0
        assert f.gamma == 1.0
        assert f.gamma_r == 1.0
        assert f.gamma_g == 1.0
        assert f.gamma_b == 1.0
        assert f.hue == 0.0
        assert f.lut_url == ""

    def test_create_all_fields(self):
        f = FilterPreset(
            id="test_002",
            name="完整滤镜",
            category="cinematic",
            description="测试描述",
            tags=["标签1", "标签2"],
            brightness=0.1,
            contrast=1.2,
            saturation=0.8,
            gamma=1.1,
            gamma_r=1.05,
            gamma_g=0.95,
            gamma_b=1.15,
            hue=10.0,
            lut_url="https://example.com/lut.png",
        )
        assert f.category == "cinematic"
        assert f.brightness == 0.1
        assert f.contrast == 1.2
        assert f.saturation == 0.8
        assert f.gamma == 1.1
        assert f.gamma_r == 1.05
        assert f.gamma_g == 0.95
        assert f.gamma_b == 1.15
        assert f.hue == 10.0
        assert f.lut_url == "https://example.com/lut.png"

    def test_frozen_immutable(self):
        f = FilterPreset(id="test", name="测试", category="basic")
        with pytest.raises(FrozenInstanceError):
            f.name = "修改"  # type: ignore[misc]

    def test_tags_default_new_list(self):
        f1 = FilterPreset(id="1", name="a", category="basic")
        f2 = FilterPreset(id="2", name="b", category="basic")
        assert f1.tags is not f2.tags
        assert f1.tags == []


class TestFilterPresetLibrary:
    """FILTER_PRESET_LIBRARY 预设库测试."""

    def test_not_empty(self):
        assert len(FILTER_PRESET_LIBRARY) > 0

    def test_all_unique_ids(self):
        ids = [f.id for f in FILTER_PRESET_LIBRARY]
        assert len(ids) == len(set(ids))

    def test_all_are_filter_preset_instances(self):
        for f in FILTER_PRESET_LIBRARY:
            assert isinstance(f, FilterPreset)

    def test_contains_basic_category(self):
        cats = {f.category for f in FILTER_PRESET_LIBRARY}
        assert "basic" in cats

    def test_none_filter_is_identity(self):
        """filter_none 应该所有参数都是默认值（不改变画面）"""
        f = get_filter_preset("filter_none")
        assert f is not None
        assert f.brightness == 0.0
        assert f.contrast == 1.0
        assert f.saturation == 1.0
        assert f.gamma == 1.0


class TestGetFilterPreset:
    """get_filter_preset 函数测试."""

    def test_existing_id(self):
        f = get_filter_preset("filter_brighten")
        assert f is not None
        assert f.id == "filter_brighten"
        assert f.name == "明亮"

    def test_nonexistent_id(self):
        assert get_filter_preset("nonexistent") is None

    def test_empty_string(self):
        assert get_filter_preset("") is None


class TestListFilterPresets:
    """list_filter_presets 函数测试."""

    def test_no_filters_returns_all(self):
        result = list_filter_presets()
        assert len(result) == len(FILTER_PRESET_LIBRARY)

    def test_filter_by_category_basic(self):
        result = list_filter_presets(category="basic")
        assert len(result) >= 4
        for f in result:
            assert f.category == "basic"

    def test_filter_by_unknown_category_returns_empty(self):
        result = list_filter_presets(category="nonexistent")
        assert result == []

    def test_filter_by_keyword_name(self):
        result = list_filter_presets(keyword="明亮")
        assert len(result) >= 1
        assert any(f.name == "明亮" for f in result)

    def test_filter_by_keyword_tag(self):
        result = list_filter_presets(keyword="提亮")
        assert len(result) >= 1

    def test_filter_by_keyword_description(self):
        result = list_filter_presets(keyword="偏暗")
        assert len(result) >= 1

    def test_filter_keyword_case_insensitive(self):
        r1 = list_filter_presets(keyword="FILTER")
        r2 = list_filter_presets(keyword="filter")
        assert len(r1) == len(r2)

    def test_filter_keyword_no_match(self):
        result = list_filter_presets(keyword="xyz_nonexistent_12345")
        assert result == []

    def test_combined_category_and_keyword(self):
        result = list_filter_presets(category="basic", keyword="明亮")
        assert len(result) >= 1
        for f in result:
            assert f.category == "basic"

    def test_combined_no_match(self):
        result = list_filter_presets(category="basic", keyword="电影感")
        # 基础分类里没有电影感关键词
        pass  # 不做强断言，看实际数据


class TestBuildFFmpegFilter:
    """build_ffmpeg_filter 函数测试."""

    def test_none_preset_returns_empty(self):
        result = build_ffmpeg_filter("nonexistent")
        assert result == ""

    def test_zero_intensity_returns_empty(self):
        result = build_ffmpeg_filter("filter_brighten", intensity=0)
        assert result == ""

    def test_negative_intensity_returns_empty(self):
        result = build_ffmpeg_filter("filter_brighten", intensity=-10)
        assert result == ""

    def test_full_intensity_brighten(self):
        result = build_ffmpeg_filter("filter_brighten", intensity=100)
        assert result.startswith("eq=")
        assert "brightness=0.120" in result
        assert "contrast=1.050" in result
        assert "saturation=1.050" in result
        assert "gamma=1.100" in result

    def test_half_intensity(self):
        """强度 50% 时参数应该是全量的一半（向原值插值）"""
        full = build_ffmpeg_filter("filter_brighten", intensity=100)
        half = build_ffmpeg_filter("filter_brighten", intensity=50)

        # 50% 强度的 brightness 应该是 0.060 (0.120 * 0.5)
        assert "brightness=0.060" in half
        # full 和 half 都应该有 eq= 前缀
        assert full.startswith("eq=")
        assert half.startswith("eq=")

    def test_intensity_over_100_clamps_to_100(self):
        result1 = build_ffmpeg_filter("filter_brighten", intensity=100)
        result2 = build_ffmpeg_filter("filter_brighten", intensity=150)
        assert result1 == result2

    def test_filter_none_returns_empty(self):
        """原图滤镜所有参数都是默认值，应该返回空字符串"""
        result = build_ffmpeg_filter("filter_none")
        assert result == ""

    def test_warm_filter_has_gamma_channels(self):
        """暖色滤镜应该调整 RGB 通道伽马"""
        result = build_ffmpeg_filter("filter_warm", intensity=100)
        assert "gamma_r=" in result
        # 暖色红通道伽马 > 1.0
        assert "gamma_r=1.100" in result

    def test_result_format_is_eq_params(self):
        """结果格式应该是 eq=param1=val:param2=val..."""
        result = build_ffmpeg_filter("filter_brighten", intensity=100)
        assert result.startswith("eq=")
        # 参数之间用冒号分隔
        parts = result[3:].split(":")
        assert len(parts) >= 4  # 至少 brightness/contrast/saturation/gamma
        for part in parts:
            assert "=" in part  # 每个部分都是 key=value 格式
