"""水印引擎单元测试 - 配置解析 + 位置计算等纯逻辑."""

from __future__ import annotations

import pytest
from video_processing.watermark_engine import (
    WATERMARK_POSITIONS,
    WatermarkConfig,
    WatermarkEngine,
)

# ── WatermarkConfig 测试 ──────────────────────────────────────────


class TestWatermarkConfigDefaults:
    """默认值测试."""

    def test_default_values(self):
        """默认配置值正确."""
        config = WatermarkConfig()
        assert config.mode == "text"
        assert config.position == "bottom_right"
        assert config.image_path == ""
        assert config.scale == 0.2
        assert config.opacity == 0.8
        assert config.text == ""
        assert config.font_size == 24
        assert config.font_color == "white"
        assert config.font_path == ""
        assert config.margin_x == 20
        assert config.margin_y == 20
        assert config.scroll is False
        assert config.scroll_speed == 50


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

    def test_none_returns_none(self):
        """None 返回 None."""
        assert WatermarkConfig.from_dict(None) is None

    def test_empty_dict_returns_none(self):
        """空字典返回 None."""
        assert WatermarkConfig.from_dict({}) is None

    def test_disabled_returns_none(self):
        """enabled=False 返回 None."""
        assert WatermarkConfig.from_dict({"enabled": False}) is None

    def test_text_mode_basic(self):
        """文字水印基本配置."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "text",
                "text": "测试水印",
            }
        )
        assert config is not None
        assert config.mode == "text"
        assert config.text == "测试水印"
        assert config.position == "bottom_right"  # 默认

    def test_text_mode_missing_text_returns_none(self):
        """文字水印缺少 text 返回 None."""
        result = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "text",
            }
        )
        assert result is None

    def test_text_mode_empty_text_returns_none(self):
        """文字水印 text 为空返回 None."""
        result = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "text",
                "text": "",
            }
        )
        assert result is None

    def test_image_mode_basic(self):
        """图片水印基本配置."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "image",
                "image_path": "/path/to/logo.png",
            }
        )
        assert config is not None
        assert config.mode == "image"
        assert config.image_path == "/path/to/logo.png"

    def test_image_mode_missing_image_returns_none(self):
        """图片水印缺少 image_path 返回 None."""
        result = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "image",
            }
        )
        assert result is None

    def test_image_mode_image_alias(self):
        """image 字段作为 image_path 的别名."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "image",
                "image": "/path/alias.png",
            }
        )
        assert config is not None
        assert config.image_path == "/path/alias.png"

    def test_invalid_position_falls_back(self):
        """无效位置 fallback 到 bottom_right."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "text",
                "text": "test",
                "position": "invalid_pos",
            }
        )
        assert config is not None
        assert config.position == "bottom_right"

    def test_custom_position_valid(self):
        """自定义有效位置."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "text",
                "text": "test",
                "position": "top_left",
            }
        )
        assert config is not None
        assert config.position == "top_left"

    def test_all_text_fields_parsed(self):
        """文字水印所有字段正确解析."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "text",
                "text": "我的水印",
                "font_size": 32,
                "font_color": "red",
                "font_path": "/fonts/msyh.ttf",
                "position": "top_center",
                "opacity": 0.5,
                "margin_x": 30,
                "margin_y": 40,
            }
        )
        assert config is not None
        assert config.text == "我的水印"
        assert config.font_size == 32
        assert config.font_color == "red"
        assert config.font_path == "/fonts/msyh.ttf"
        assert config.position == "top_center"
        assert config.opacity == 0.5
        assert config.margin_x == 30
        assert config.margin_y == 40

    def test_all_image_fields_parsed(self):
        """图片水印所有字段正确解析."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "image",
                "image_path": "/img/logo.png",
                "scale": 0.3,
                "opacity": 0.9,
                "position": "bottom_left",
                "margin_x": 10,
                "margin_y": 15,
            }
        )
        assert config is not None
        assert config.image_path == "/img/logo.png"
        assert config.scale == 0.3
        assert config.opacity == 0.9
        assert config.position == "bottom_left"

    def test_scroll_config_parsed(self):
        """滚动水印配置解析."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "mode": "text",
                "text": "滚动水印",
                "scroll": True,
                "scroll_speed": 80,
            }
        )
        assert config is not None
        assert config.scroll is True
        assert config.scroll_speed == 80

    def test_default_mode_is_text(self):
        """不传 mode 默认为 text."""
        config = WatermarkConfig.from_dict(
            {
                "enabled": True,
                "text": "默认模式",
            }
        )
        assert config is not None
        assert config.mode == "text"


class TestWatermarkConfigValidate:
    """validate 配置校验测试."""

    def test_valid_text_config(self):
        """合法文字水印配置."""
        config = WatermarkConfig(mode="text", text="测试", position="bottom_right")
        ok, msg = config.validate()
        assert ok is True
        assert msg == ""

    def test_valid_image_config(self):
        """合法图片水印配置."""
        config = WatermarkConfig(
            mode="image",
            image_path="/a.png",
            position="top_left",
            scale=0.3,
            opacity=0.8,
        )
        ok, msg = config.validate()
        assert ok is True

    def test_invalid_position(self):
        """无效位置."""
        config = WatermarkConfig(mode="text", text="test", position="invalid")
        ok, msg = config.validate()
        assert ok is False
        assert "不支持的位置" in msg

    def test_opacity_too_high(self):
        """透明度超过1."""
        config = WatermarkConfig(mode="text", text="test", opacity=1.5)
        ok, msg = config.validate()
        assert ok is False
        assert "透明度" in msg

    def test_opacity_negative(self):
        """透明度为负."""
        config = WatermarkConfig(mode="text", text="test", opacity=-0.1)
        ok, msg = config.validate()
        assert ok is False
        assert "透明度" in msg

    def test_opacity_boundary_zero(self):
        """透明度边界值0."""
        config = WatermarkConfig(mode="text", text="test", opacity=0.0)
        ok, _ = config.validate()
        assert ok is True

    def test_opacity_boundary_one(self):
        """透明度边界值1."""
        config = WatermarkConfig(mode="text", text="test", opacity=1.0)
        ok, _ = config.validate()
        assert ok is True

    def test_image_missing_path(self):
        """图片水印缺少路径."""
        config = WatermarkConfig(mode="image", image_path="")
        ok, msg = config.validate()
        assert ok is False
        assert "图片路径" in msg

    def test_image_scale_too_small(self):
        """缩放比例太小."""
        config = WatermarkConfig(mode="image", image_path="/a.png", scale=0.001)
        ok, msg = config.validate()
        assert ok is False
        assert "缩放比例" in msg

    def test_image_scale_too_large(self):
        """缩放比例太大."""
        config = WatermarkConfig(mode="image", image_path="/a.png", scale=2.0)
        ok, msg = config.validate()
        assert ok is False
        assert "缩放比例" in msg

    def test_image_scale_boundary_low(self):
        """缩放边界低值."""
        config = WatermarkConfig(mode="image", image_path="/a.png", scale=0.01)
        ok, _ = config.validate()
        assert ok is True

    def test_image_scale_boundary_high(self):
        """缩放边界高值."""
        config = WatermarkConfig(mode="image", image_path="/a.png", scale=1.0)
        ok, _ = config.validate()
        assert ok is True

    def test_text_missing_content(self):
        """文字水印缺少内容."""
        config = WatermarkConfig(mode="text", text="")
        ok, msg = config.validate()
        assert ok is False
        assert "文字内容" in msg

    def test_text_font_size_zero(self):
        """字体大小为0."""
        config = WatermarkConfig(mode="text", text="test", font_size=0)
        ok, msg = config.validate()
        assert ok is False
        assert "字体大小" in msg

    def test_text_font_size_negative(self):
        """字体大小为负."""
        config = WatermarkConfig(mode="text", text="test", font_size=-5)
        ok, msg = config.validate()
        assert ok is False
        assert "字体大小" in msg

    def test_unknown_mode(self):
        """未知模式."""
        config = WatermarkConfig(mode="unknown_mode")
        ok, msg = config.validate()
        assert ok is False
        assert "不支持的水印模式" in msg


# ── WatermarkEngine 位置计算测试 ────────────────────────────────


class TestCalcPosition:
    """9宫格位置计算测试."""

    # 测试用：输出 1920x1080，水印 200x100，边距 20
    W, H = 1920, 1080
    WW, WH = 200, 100
    MX, MY = 20, 20

    def test_top_left(self):
        """左上角."""
        x, y = WatermarkEngine.calc_position("top_left", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert (x, y) == (20, 20)

    def test_top_center(self):
        """中上."""
        x, y = WatermarkEngine.calc_position("top_center", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == (1920 - 200) // 2
        assert y == 20

    def test_top_right(self):
        """右上角."""
        x, y = WatermarkEngine.calc_position("top_right", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == 1920 - 200 - 20
        assert y == 20

    def test_center_left(self):
        """左中."""
        x, y = WatermarkEngine.calc_position("center_left", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == 20
        assert y == (1080 - 100) // 2

    def test_center(self):
        """中心."""
        x, y = WatermarkEngine.calc_position("center", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == (1920 - 200) // 2
        assert y == (1080 - 100) // 2

    def test_center_right(self):
        """右中."""
        x, y = WatermarkEngine.calc_position("center_right", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == 1920 - 200 - 20
        assert y == (1080 - 100) // 2

    def test_bottom_left(self):
        """左下角."""
        x, y = WatermarkEngine.calc_position("bottom_left", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == 20
        assert y == 1080 - 100 - 20

    def test_bottom_center(self):
        """中下."""
        x, y = WatermarkEngine.calc_position("bottom_center", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == (1920 - 200) // 2
        assert y == 1080 - 100 - 20

    def test_bottom_right(self):
        """右下角."""
        x, y = WatermarkEngine.calc_position("bottom_right", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == 1920 - 200 - 20
        assert y == 1080 - 100 - 20

    def test_unknown_position_defaults_bottom_right(self):
        """未知位置默认右下角."""
        x, y = WatermarkEngine.calc_position("unknown", self.W, self.H, self.WW, self.WH, self.MX, self.MY)
        assert x == 1920 - 200 - 20
        assert y == 1080 - 100 - 20

    def test_zero_margin(self):
        """零边距."""
        x, y = WatermarkEngine.calc_position("top_left", 1000, 500, 100, 50, 0, 0)
        assert (x, y) == (0, 0)

    def test_small_output(self):
        """小尺寸输出."""
        x, y = WatermarkEngine.calc_position("bottom_right", 320, 240, 50, 30, 5, 5)
        assert x == 320 - 50 - 5
        assert y == 240 - 30 - 5


class TestCalcScrollX:
    """滚动水印x坐标表达式测试."""

    def test_returns_string_expression(self):
        """返回字符串表达式."""
        expr = WatermarkEngine.calc_scroll_x("bottom_right", 1920, 200, 50)
        assert isinstance(expr, str)
        assert "1920" in expr
        assert "200" in expr
        assert "50" in expr

    def test_contains_mod_function(self):
        """包含 mod 函数."""
        expr = WatermarkEngine.calc_scroll_x("top_left", 1280, 150, 60)
        assert "mod(" in expr
        assert "t" in expr  # 时间变量


class TestWatermarkPositions:
    """位置常量测试."""

    def test_nine_positions(self):
        """共9个位置."""
        assert len(WATERMARK_POSITIONS) == 9

    def test_all_position_keys_valid(self):
        """所有位置键名正确."""
        expected = {
            "top_left",
            "top_center",
            "top_right",
            "center_left",
            "center",
            "center_right",
            "bottom_left",
            "bottom_center",
            "bottom_right",
        }
        assert set(WATERMARK_POSITIONS.keys()) == expected
