"""调色引擎单元测试 - 配置解析等纯逻辑."""

from __future__ import annotations

import pytest
from video_processing.color_grade_engine import (
    DEFAULT_PARAMS,
    PARAM_RANGES,
    PRESET_PARAMS,
    VALID_PRESETS,
    ColorGradeConfig,
)


class TestColorGradeConfigDefaults:
    """默认配置测试."""

    def test_default_values(self):
        """默认值正确."""
        config = ColorGradeConfig()
        assert config.enabled is False
        assert config.preset == ""
        assert config.brightness is None
        assert config.contrast is None
        assert config.saturation is None
        assert config.temperature is None
        assert config.hue is None


class TestColorGradeConfigFromDict:
    """from_dict 配置解析测试."""

    def test_none_returns_disabled(self):
        """None 返回禁用配置."""
        config = ColorGradeConfig.from_dict(None)
        assert config.enabled is False

    def test_empty_dict_returns_disabled(self):
        """空字典返回禁用."""
        config = ColorGradeConfig.from_dict({})
        assert config.enabled is False

    def test_disabled_returns_disabled(self):
        """enabled=False 返回禁用."""
        config = ColorGradeConfig.from_dict({"enabled": False})
        assert config.enabled is False

    def test_enabled_no_params(self):
        """启用但无自定义参数."""
        config = ColorGradeConfig.from_dict({"enabled": True})
        assert config.enabled is True
        assert config.preset == ""
        assert config.brightness is None

    def test_with_preset(self):
        """指定预设."""
        config = ColorGradeConfig.from_dict(
            {
                "enabled": True,
                "preset": "fresh",
            }
        )
        assert config.enabled is True
        assert config.preset == "fresh"

    def test_invalid_preset_ignored(self):
        """无效预设被忽略."""
        config = ColorGradeConfig.from_dict(
            {
                "enabled": True,
                "preset": "unknown_preset",
            }
        )
        assert config.preset == ""

    def test_custom_brightness(self):
        """自定义亮度."""
        config = ColorGradeConfig.from_dict(
            {
                "enabled": True,
                "brightness": 20,
            }
        )
        assert config.brightness == 20.0

    def test_custom_all_params(self):
        """所有参数自定义."""
        config = ColorGradeConfig.from_dict(
            {
                "enabled": True,
                "brightness": 10,
                "contrast": 15,
                "saturation": 120,
                "temperature": -5,
                "hue": 10,
            }
        )
        assert config.brightness == 10.0
        assert config.contrast == 15.0
        assert config.saturation == 120.0
        assert config.temperature == -5.0
        assert config.hue == 10.0

    def test_invalid_param_value_returns_none(self):
        """无效参数值返回None（不覆盖）."""
        config = ColorGradeConfig.from_dict(
            {
                "enabled": True,
                "brightness": "not_a_number",
            }
        )
        assert config.brightness is None

    def test_null_param_returns_none(self):
        """null参数值返回None."""
        config = ColorGradeConfig.from_dict(
            {
                "enabled": True,
                "contrast": None,
            }
        )
        assert config.contrast is None

    def test_preset_with_custom_override(self):
        """预设 + 自定义覆盖."""
        config = ColorGradeConfig.from_dict(
            {
                "enabled": True,
                "preset": "vintage",
                "brightness": 5,
            }
        )
        assert config.preset == "vintage"
        assert config.brightness == 5.0


class TestResolveParams:
    """resolve_params 参数解析测试."""

    def test_disabled_returns_defaults(self):
        """禁用配置也返回默认参数."""
        config = ColorGradeConfig(enabled=False)
        params = config.resolve_params()
        for key, val in DEFAULT_PARAMS.items():
            assert params[key] == val

    def test_no_preset_no_custom_returns_defaults(self):
        """无预设无自定义返回默认值."""
        config = ColorGradeConfig(enabled=True)
        params = config.resolve_params()
        for key, val in DEFAULT_PARAMS.items():
            assert abs(params[key] - val) < 0.001

    def test_preset_applies_params(self):
        """预设应用参数."""
        config = ColorGradeConfig(enabled=True, preset="fresh")
        params = config.resolve_params()
        # 清新预设亮度=8
        assert params["brightness"] == 8
        assert params["saturation"] == 120

    def test_custom_overrides_preset(self):
        """自定义参数覆盖预设."""
        config = ColorGradeConfig(
            enabled=True,
            preset="fresh",
            brightness=50,  # 覆盖预设的8
        )
        params = config.resolve_params()
        assert params["brightness"] == 50
        # 其他参数仍用预设值
        assert params["saturation"] == 120

    def test_brightness_clamped(self):
        """亮度边界钳制."""
        config = ColorGradeConfig(enabled=True, brightness=200)
        params = config.resolve_params()
        assert params["brightness"] == 100.0

    def test_saturation_clamped_low(self):
        """饱和度下限钳制."""
        config = ColorGradeConfig(enabled=True, saturation=-10)
        params = config.resolve_params()
        assert params["saturation"] == 0.0

    def test_saturation_clamped_high(self):
        """饱和度上限钳制."""
        config = ColorGradeConfig(enabled=True, saturation=300)
        params = config.resolve_params()
        assert params["saturation"] == 200.0

    def test_hue_clamped(self):
        """色调边界钳制."""
        config = ColorGradeConfig(enabled=True, hue=200)
        params = config.resolve_params()
        assert params["hue"] == 180.0

    def test_hue_negative_clamped(self):
        """负色调边界钳制."""
        config = ColorGradeConfig(enabled=True, hue=-200)
        params = config.resolve_params()
        assert params["hue"] == -180.0

    def test_returns_all_five_params(self):
        """返回所有5个参数."""
        config = ColorGradeConfig(enabled=True)
        params = config.resolve_params()
        assert set(params.keys()) == {"brightness", "contrast", "saturation", "temperature", "hue"}


class TestHasEffect:
    """has_effect 方法测试."""

    def test_default_no_effect(self):
        """默认配置无效果."""
        config = ColorGradeConfig(enabled=True)
        assert config.has_effect() is False

    def test_with_preset_has_effect(self):
        """有预设时有效果."""
        config = ColorGradeConfig(enabled=True, preset="cinema")
        assert config.has_effect() is True

    def test_custom_brightness_has_effect(self):
        """自定义亮度有效果."""
        config = ColorGradeConfig(enabled=True, brightness=10)
        assert config.has_effect() is True

    def test_disabled_still_checks_params(self):
        """禁用也根据参数判断（结果仍可能有效果但不启用）."""
        # has_effect 只看参数，不看 enabled
        config = ColorGradeConfig(enabled=False, preset="warm")
        assert config.has_effect() is True

    def test_black_white_preset_has_effect(self):
        """黑白预设（饱和度=0）有效果."""
        config = ColorGradeConfig(enabled=True, preset="black_white")
        assert config.has_effect() is True


class TestPresets:
    """预设常量测试."""

    def test_eight_valid_presets(self):
        """8个有效预设."""
        assert len(VALID_PRESETS) == 8

    def test_preset_params_match_valid(self):
        """所有预设都在有效列表中."""
        for name in PRESET_PARAMS:
            assert name in VALID_PRESETS

    def test_each_preset_has_all_params(self):
        """每个预设包含所有5个参数."""
        for name, params in PRESET_PARAMS.items():
            for key in ["brightness", "contrast", "saturation", "temperature", "hue"]:
                assert key in params, f"{name} missing {key}"

    def test_param_ranges_defined(self):
        """参数范围定义完整."""
        assert set(PARAM_RANGES.keys()) == {"brightness", "contrast", "saturation", "temperature", "hue"}
