"""画中画引擎单元测试 - 配置解析+校验等纯逻辑."""

from __future__ import annotations

import pytest
from video_processing.pip_engine import PiPConfig, PiPLayerConfig


class TestPiPLayerConfigDefaults:
    """PiPLayerConfig 默认配置测试."""

    def test_default_values(self):
        """默认值正确."""
        layer = PiPLayerConfig()
        assert layer.source == ""
        assert layer.source_type == "asset_id"
        assert layer.position == "bottom_right"
        assert layer.margin == 20
        assert layer.width == "25%"
        assert layer.height == ""
        assert layer.opacity == 1.0
        assert layer.corner_radius == 0
        assert layer.border_width == 0
        assert layer.border_color == "white"
        assert layer.start_time == 0.0
        assert layer.duration == 0.0
        assert layer.animation_in == ""
        assert layer.animation_out == ""
        assert layer.animation_duration == 0.5
        assert layer.z_index == 1


class TestPiPLayerConfigValidate:
    """PiPLayerConfig.validate 校验测试."""

    def test_valid_config(self):
        """合法配置."""
        layer = PiPLayerConfig(source="asset_123")
        ok, msg = layer.validate()
        assert ok is True
        assert msg == ""

    def test_empty_source_invalid(self):
        """空source非法."""
        layer = PiPLayerConfig(source="")
        ok, msg = layer.validate()
        assert ok is False
        assert "source" in msg

    def test_invalid_position(self):
        """无效position."""
        layer = PiPLayerConfig(source="asset_123", position="invalid_pos")
        ok, msg = layer.validate()
        assert ok is False
        assert "position" in msg

    def test_custom_position_valid(self):
        """custom位置合法."""
        layer = PiPLayerConfig(
            source="asset_123",
            position="custom",
            x=100,
            y=100,
        )
        ok, _ = layer.validate()
        assert ok is True

    def test_opacity_too_high(self):
        """透明度超过1."""
        layer = PiPLayerConfig(source="a", opacity=1.5)
        ok, msg = layer.validate()
        assert ok is False
        assert "opacity" in msg

    def test_opacity_negative(self):
        """透明度为负."""
        layer = PiPLayerConfig(source="a", opacity=-0.1)
        ok, msg = layer.validate()
        assert ok is False
        assert "opacity" in msg

    def test_opacity_boundary_zero(self):
        """透明度边界值0."""
        layer = PiPLayerConfig(source="a", opacity=0.0)
        ok, _ = layer.validate()
        assert ok is True

    def test_opacity_boundary_one(self):
        """透明度边界值1."""
        layer = PiPLayerConfig(source="a", opacity=1.0)
        ok, _ = layer.validate()
        assert ok is True

    def test_negative_corner_radius(self):
        """负圆角."""
        layer = PiPLayerConfig(source="a", corner_radius=-5)
        ok, msg = layer.validate()
        assert ok is False
        assert "corner_radius" in msg

    def test_negative_start_time(self):
        """负开始时间."""
        layer = PiPLayerConfig(source="a", start_time=-1.0)
        ok, msg = layer.validate()
        assert ok is False
        assert "start_time" in msg

    def test_negative_duration(self):
        """负时长."""
        layer = PiPLayerConfig(source="a", duration=-2.0)
        ok, msg = layer.validate()
        assert ok is False
        assert "duration" in msg

    def test_zero_duration_valid(self):
        """零时长（全程显示）合法."""
        layer = PiPLayerConfig(source="a", duration=0.0)
        ok, _ = layer.validate()
        assert ok is True

    def test_invalid_animation_in(self):
        """无效入场动画."""
        layer = PiPLayerConfig(source="a", animation_in="invalid_anim")
        ok, msg = layer.validate()
        assert ok is False
        assert "入场动画" in msg

    def test_invalid_animation_out(self):
        """无效出场动画."""
        layer = PiPLayerConfig(source="a", animation_out="invalid_anim")
        ok, msg = layer.validate()
        assert ok is False
        assert "出场动画" in msg

    def test_negative_animation_duration(self):
        """负动画时长."""
        layer = PiPLayerConfig(source="a", animation_duration=-0.5)
        ok, msg = layer.validate()
        assert ok is False
        assert "animation_duration" in msg


class TestPiPConfigDefaults:
    """PiPConfig 默认配置测试."""

    def test_default_values(self):
        """默认值正确."""
        config = PiPConfig()
        assert config.enabled is False
        assert config.layers == []


class TestPiPConfigFromDict:
    """PiPConfig.from_dict 解析测试."""

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

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

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

    def test_enabled_no_layers(self):
        """启用但无图层，disabled."""
        config = PiPConfig.from_dict({"enabled": True, "layers": []})
        assert config.enabled is False
        assert config.layers == []

    def test_single_layer(self):
        """单个图层."""
        config = PiPConfig.from_dict(
            {
                "enabled": True,
                "layers": [
                    {"source": "asset_001", "position": "top_left"},
                ],
            }
        )
        assert config.enabled is True
        assert len(config.layers) == 1
        assert config.layers[0].source == "asset_001"
        assert config.layers[0].position == "top_left"

    def test_multiple_layers_sorted_by_z_index(self):
        """多个图层按z_index排序."""
        config = PiPConfig.from_dict(
            {
                "enabled": True,
                "layers": [
                    {"source": "a", "z_index": 3},
                    {"source": "b", "z_index": 1},
                    {"source": "c", "z_index": 2},
                ],
            }
        )
        assert len(config.layers) == 3
        assert config.layers[0].z_index == 1
        assert config.layers[1].z_index == 2
        assert config.layers[2].z_index == 3

    def test_invalid_layer_skipped(self):
        """无效图层跳过."""
        config = PiPConfig.from_dict(
            {
                "enabled": True,
                "layers": [
                    {"source": "valid_asset"},
                    {"source": ""},  # 无效，空source
                ],
            }
        )
        assert len(config.layers) == 1
        assert config.layers[0].source == "valid_asset"

    def test_all_invalid_layers_disabled(self):
        """全部无效则disabled."""
        config = PiPConfig.from_dict(
            {
                "enabled": True,
                "layers": [
                    {"source": ""},
                    {"source": ""},
                ],
            }
        )
        assert config.enabled is False
        assert config.layers == []

    def test_layer_full_config(self):
        """完整图层配置."""
        config = PiPConfig.from_dict(
            {
                "enabled": True,
                "layers": [
                    {
                        "source": "https://example.com/video.mp4",
                        "source_type": "url",
                        "position": "bottom_right",
                        "width": "30%",
                        "opacity": 0.8,
                        "corner_radius": 10,
                        "border_width": 2,
                        "border_color": "red",
                        "start_time": 5.0,
                        "duration": 10.0,
                        "z_index": 5,
                    },
                ],
            }
        )
        assert len(config.layers) == 1
        layer = config.layers[0]
        assert layer.source == "https://example.com/video.mp4"
        assert layer.source_type == "url"
        assert layer.width == "30%"
        assert layer.opacity == 0.8
        assert layer.corner_radius == 10
        assert layer.border_width == 2
        assert layer.border_color == "red"
        assert layer.start_time == 5.0
        assert layer.duration == 10.0
        assert layer.z_index == 5
