"""edit_template 剪辑模板实体单测."""

from datetime import datetime, timezone

import pytest
from domain.edit_template import EditTemplate, EditTemplateStatus
from domain.editing_mode import EditingMode

# ── EditTemplateStatus 枚举 ──────────────────────────────────────────────────


class TestEditTemplateStatus:
    """EditTemplateStatus 枚举"""

    def test_enum_values(self):
        assert EditTemplateStatus.ACTIVE.value == "active"
        assert EditTemplateStatus.INACTIVE.value == "inactive"

    def test_is_str_enum(self):
        assert isinstance(EditTemplateStatus.ACTIVE, str)
        assert EditTemplateStatus.ACTIVE == "active"

    def test_from_string(self):
        assert EditTemplateStatus("active") == EditTemplateStatus.ACTIVE
        assert EditTemplateStatus("inactive") == EditTemplateStatus.INACTIVE

    def test_invalid_raises(self):
        with pytest.raises(ValueError):
            EditTemplateStatus("deleted")


# ── EditTemplate.create 工厂方法 ────────────────────────────────────────────


class TestEditTemplateCreate:
    """EditTemplate.create 工厂方法"""

    def test_minimal_create(self):
        t = EditTemplate.create("测试模板")
        assert t.id is not None
        assert len(t.id) == 32  # uuid4 hex
        assert t.name == "测试模板"
        assert t.description == ""
        assert t.template_type == "default"
        assert t.editing_mode == "one_take"
        assert t.config == {}
        assert t.preview_url == ""
        assert t.sort_weight == 0
        assert t.status == EditTemplateStatus.ACTIVE
        assert t.version == 1

    def test_unique_ids(self):
        t1 = EditTemplate.create("模板A")
        t2 = EditTemplate.create("模板B")
        assert t1.id != t2.id

    def test_custom_fields(self):
        t = EditTemplate.create(
            "自定义模板",
            description="这是一个自定义模板",
            template_type="story",
            editing_mode="one_take",
            config={"key": "value"},
            preview_url="https://example.com/preview.mp4",
            sort_weight=100,
            status=EditTemplateStatus.INACTIVE,
            version=2,
        )
        assert t.name == "自定义模板"
        assert t.description == "这是一个自定义模板"
        assert t.template_type == "story"
        assert t.editing_mode == "one_take"
        assert t.config == {"key": "value"}
        assert t.preview_url == "https://example.com/preview.mp4"
        assert t.sort_weight == 100
        assert t.status == EditTemplateStatus.INACTIVE
        assert t.version == 2

    def test_name_stripped(self):
        t = EditTemplate.create("  带空格的模板  ")
        assert t.name == "带空格的模板"

    def test_empty_name_raises(self):
        with pytest.raises(ValueError, match="名称"):
            EditTemplate.create("")

    def test_whitespace_only_name_raises(self):
        with pytest.raises(ValueError):
            EditTemplate.create("   ")

    def test_invalid_editing_mode_raises(self):
        with pytest.raises(ValueError, match="editing_mode"):
            EditTemplate.create("测试", editing_mode="invalid_mode")

    def test_empty_editing_mode_falls_back_to_default(self):
        t = EditTemplate.create("测试", editing_mode="")
        assert t.editing_mode == "one_take"

    def test_whitespace_editing_mode_falls_back(self):
        t = EditTemplate.create("测试", editing_mode="   ")
        assert t.editing_mode == "one_take"

    def test_editing_mode_stripped(self):
        t = EditTemplate.create("测试", editing_mode=" one_take ")
        assert t.editing_mode == "one_take"

    def test_description_stripped(self):
        t = EditTemplate.create("测试", description="  描述  ")
        assert t.description == "描述"

    def test_template_type_stripped(self):
        t = EditTemplate.create("测试", template_type="  vlog  ")
        assert t.template_type == "vlog"

    def test_empty_template_type_falls_back(self):
        t = EditTemplate.create("测试", template_type="")
        assert t.template_type == "default"

    def test_none_config_becomes_empty_dict(self):
        t = EditTemplate.create("测试", config=None)
        assert t.config == {}
        assert isinstance(t.config, dict)

    def test_preview_url_stripped(self):
        t = EditTemplate.create("测试", preview_url="  https://x.com/a.mp4  ")
        assert t.preview_url == "https://x.com/a.mp4"

    def test_timestamps_are_utc(self):
        t = EditTemplate.create("测试")
        assert t.created_at.tzinfo is not None
        assert t.updated_at.tzinfo is not None

    def test_created_at_equals_updated_at_on_create(self):
        t = EditTemplate.create("测试")
        # 创建时两个时间应该非常接近
        diff = abs((t.updated_at - t.created_at).total_seconds())
        assert diff < 1.0


# ── 状态操作 ─────────────────────────────────────────────────────────────────


class TestEditTemplateStatusOperations:
    """EditTemplate 状态操作"""

    def test_activate_sets_active(self):
        t = EditTemplate.create("测试", status=EditTemplateStatus.INACTIVE)
        t.activate()
        assert t.status == EditTemplateStatus.ACTIVE
        assert t.is_active is True

    def test_deactivate_sets_inactive(self):
        t = EditTemplate.create("测试")
        t.deactivate()
        assert t.status == EditTemplateStatus.INACTIVE
        assert t.is_active is False

    def test_is_active_true(self):
        t = EditTemplate.create("测试")
        assert t.is_active is True

    def test_is_active_false(self):
        t = EditTemplate.create("测试", status=EditTemplateStatus.INACTIVE)
        assert t.is_active is False

    def test_activate_updates_updated_at(self):
        t = EditTemplate.create("测试", status=EditTemplateStatus.INACTIVE)
        old_updated = t.updated_at
        t.activate()
        assert t.updated_at >= old_updated

    def test_deactivate_updates_updated_at(self):
        t = EditTemplate.create("测试")
        old_updated = t.updated_at
        t.deactivate()
        assert t.updated_at >= old_updated


# ── 版本操作 ─────────────────────────────────────────────────────────────────


class TestEditTemplateVersion:
    """EditTemplate 版本操作"""

    def test_bump_version_increments(self):
        t = EditTemplate.create("测试")
        assert t.version == 1
        t.bump_version()
        assert t.version == 2

    def test_bump_version_multiple(self):
        t = EditTemplate.create("测试", version=5)
        t.bump_version()
        t.bump_version()
        t.bump_version()
        assert t.version == 8

    def test_bump_version_updates_updated_at(self):
        t = EditTemplate.create("测试")
        old_updated = t.updated_at
        t.bump_version()
        assert t.updated_at >= old_updated


# ── dataclass 基础特性 ───────────────────────────────────────────────────────


class TestEditTemplateBasics:
    """EditTemplate 基础特性"""

    def test_slots_no_extra_attrs(self):
        t = EditTemplate.create("测试")
        with pytest.raises(AttributeError):
            t.nonexistent_field = "value"

    def test_direct_construction_minimal(self):
        # 最小构造：仅必填字段 + 状态，其余走默认值
        t = EditTemplate(
            id="custom_id",
            name="直接构造",
            status=EditTemplateStatus.ACTIVE,
        )
        assert t.id == "custom_id"
        assert t.name == "直接构造"
        assert t.status == EditTemplateStatus.ACTIVE
        # 默认值检查
        assert t.description == ""
        assert t.config == {}
        assert t.version == 1
        assert t.editing_mode == EditingMode.ONE_TAKE.value
        assert isinstance(t.created_at, datetime)
        assert isinstance(t.updated_at, datetime)

    def test_direct_construction_full(self):
        # 完整构造：所有字段都传
        now = datetime(2025, 1, 1, tzinfo=timezone.utc)
        t = EditTemplate(
            id="full_id",
            name="完整构造",
            description="测试描述",
            template_type="custom",
            editing_mode=EditingMode.PIP.value,
            config={"key": "value"},
            preview_url="https://example.com/preview.jpg",
            sort_weight=100,
            status=EditTemplateStatus.INACTIVE,
            version=3,
            created_at=now,
            updated_at=now,
        )
        assert t.id == "full_id"
        assert t.name == "完整构造"
        assert t.description == "测试描述"
        assert t.template_type == "custom"
        assert t.editing_mode == EditingMode.PIP.value
        assert t.config == {"key": "value"}
        assert t.preview_url == "https://example.com/preview.jpg"
        assert t.sort_weight == 100
        assert t.status == EditTemplateStatus.INACTIVE
        assert t.version == 3
        assert t.created_at == now
        assert t.updated_at == now

    def test_config_is_independent(self):
        # 不同实例的 config 应该是独立的 dict
        t1 = EditTemplate.create("模板1")
        t2 = EditTemplate.create("模板2")
        t1.config["key"] = "value"
        assert "key" not in t2.config

    def test_equality(self):
        # 两个不同实例即使内容相同也不等（id不同）
        t1 = EditTemplate.create("同名模板")
        t2 = EditTemplate.create("同名模板")
        assert t1 != t2

    def test_same_id_equal(self):
        now = datetime.now(timezone.utc)
        t1 = EditTemplate(id="same", name="同名", created_at=now, updated_at=now)
        t2 = EditTemplate(id="same", name="同名", created_at=now, updated_at=now)
        assert t1 == t2
