"""Unit tests for Phase 8 EditTemplate and EditPlan domain entities + repositories."""

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "api"))

import logging

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from packages.adapters.sqlalchemy_impl.edit_plan_repository import (
    SQLAlchemyEditPlanRepository,
)
from packages.adapters.sqlalchemy_impl.edit_template_repository import (
    SQLAlchemyEditTemplateRepository,
)
from packages.adapters.sqlalchemy_impl.models import Base
from packages.domain.edit_plan import EditPlan, EditPlanStatus
from packages.domain.edit_template import EditTemplate, EditTemplateStatus

logger = logging.getLogger(__name__)


# ── EditTemplate 领域实体测试 ──────────────────────────────────────────


class TestEditTemplate:
    def test_create_success(self):
        t = EditTemplate.create("vlog模板", description="日常vlog", template_type="vlog")
        assert t.name == "vlog模板"
        assert t.description == "日常vlog"
        assert t.template_type == "vlog"
        assert t.status == EditTemplateStatus.ACTIVE
        assert t.config == {}
        assert t.sort_weight == 0
        assert t.id  # 自动生成

    def test_create_strips_whitespace(self):
        t = EditTemplate.create("  模板  ")
        assert t.name == "模板"

    def test_create_empty_name_raises(self):
        try:
            EditTemplate.create("   ")
            raise AssertionError("应该抛出 ValueError")
        except ValueError as e:
            assert "模板名称不能为空" in str(e)

    def test_activate_deactivate(self):
        t = EditTemplate.create("test")
        assert t.is_active is True
        t.deactivate()
        assert t.is_active is False
        assert t.status == EditTemplateStatus.INACTIVE
        t.activate()
        assert t.is_active is True
        assert t.status == EditTemplateStatus.ACTIVE


# ── EditPlan 领域实体测试 ──────────────────────────────────────────────


class TestEditPlan:
    def test_create_success(self):
        p = EditPlan.create("tpl-1", "我的计划", config={"bgm": "happy"})
        assert p.template_id == "tpl-1"
        assert p.name == "我的计划"
        assert p.status == EditPlanStatus.DRAFT
        assert p.config == {"bgm": "happy"}
        assert p.total_duration == 0.0

    def test_create_empty_name_raises(self):
        try:
            EditPlan.create("tpl-1", "  ")
            raise AssertionError("应该抛出 ValueError")
        except ValueError as e:
            assert "计划名称不能为空" in str(e)

    def test_create_empty_template_id_raises(self):
        try:
            EditPlan.create("  ", "test")
            raise AssertionError("应该抛出 ValueError")
        except ValueError as e:
            assert "template_id 不能为空" in str(e)

    def test_status_transitions_happy_path(self):
        p = EditPlan.create("tpl-1", "test")
        assert p.status == EditPlanStatus.DRAFT

        p.start_editing()
        assert p.status == EditPlanStatus.EDITING

        p.start_rendering()
        assert p.status == EditPlanStatus.RENDERING

        p.mark_completed()
        assert p.status == EditPlanStatus.COMPLETED

    def test_status_transitions_failure_path(self):
        p = EditPlan.create("tpl-1", "test")
        p.start_editing()
        p.start_rendering()
        p.mark_failed()
        assert p.status == EditPlanStatus.FAILED

        p.reset_to_draft()
        assert p.status == EditPlanStatus.DRAFT

    def test_invalid_transition_raises(self):
        p = EditPlan.create("tpl-1", "test")
        try:
            p.start_rendering()  # draft → rendering 不合法
            raise AssertionError("应该抛出 ValueError")
        except ValueError as e:
            logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)

    def test_mark_completed_from_non_rendering_raises(self):
        p = EditPlan.create("tpl-1", "test")
        try:
            p.mark_completed()  # draft → completed 不合法
            raise AssertionError("应该抛出 ValueError")
        except ValueError as e:
            logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)

    def test_reset_from_non_failed_raises(self):
        p = EditPlan.create("tpl-1", "test")
        try:
            p.reset_to_draft()  # draft → draft 不合法
            raise AssertionError("应该抛出 ValueError")
        except ValueError as e:
            logger.warning(f"Operation failed in tests/unit/test_phase8_edit_models.py: {e}", exc_info=True)


# ── Repository 集成测试（内存 SQLite） ─────────────────────────────────


class TestRepositories:
    def _make_session(self):
        engine = create_engine("sqlite:///:memory:")
        Base.metadata.create_all(engine)
        SessionLocal = sessionmaker(bind=engine)
        return SessionLocal()

    def test_edit_template_repository_crud(self):
        session = self._make_session()
        try:
            repo = SQLAlchemyEditTemplateRepository(session)

            t = EditTemplate.create("模板A", description="测试模板")
            repo.create(t)

            fetched = repo.get(t.id)
            assert fetched is not None
            assert fetched.name == "模板A"
            assert fetched.description == "测试模板"

            # list
            active = repo.list_active()
            assert len(active) == 1
            assert active[0].id == t.id

            # update
            fetched.deactivate()
            repo.update(fetched)
            assert repo.get(t.id).status == EditTemplateStatus.INACTIVE
            assert len(repo.list_active()) == 0

            # count
            assert repo.count() == 1

            # delete
            assert repo.delete(t.id) is True
            assert repo.get(t.id) is None
            assert repo.count() == 0
        finally:
            session.close()

    def test_edit_plan_repository_crud(self):
        session = self._make_session()
        try:
            repo = SQLAlchemyEditPlanRepository(session)

            p = EditPlan.create("tpl-1", "计划A", config={"key": "val"})
            repo.create(p)

            fetched = repo.get(p.id)
            assert fetched is not None
            assert fetched.name == "计划A"
            assert fetched.config == {"key": "val"}
            assert fetched.status == EditPlanStatus.DRAFT

            # list_by_template
            plans = repo.list_by_template("tpl-1")
            assert len(plans) == 1

            # update status
            fetched.start_editing()
            repo.update(fetched)
            editing = repo.list_by_template("tpl-1", status=EditPlanStatus.EDITING)
            assert len(editing) == 1

            # count
            assert repo.count() == 1
            assert repo.count(status=EditPlanStatus.EDITING) == 1
            assert repo.count(status=EditPlanStatus.DRAFT) == 0

            # delete
            assert repo.delete(p.id) is True
            assert repo.get(p.id) is None
        finally:
            session.close()
