"""F3b 模板库 repo 单测（契约 §F3）。

`TemplateRepo` = 单用户提示词模板的 list/create/delete，统一按 `owner_id` 过滤
（单用户原型 stub）。`create`/`delete` 只 `flush()` 不 `commit()`——提交交端点事务
（与项目其它写侧 repo 一致，见 memory/gotchas）。`delete` 返回是否删到行（端点据此 404）。
纯内存 fake，无 DB。
"""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field

import pytest
from pydantic import ValidationError
from ww_core.domain.template_repo import TemplateCreate, TemplateRepo, TemplateView

OWNER = uuid.UUID(int=1)
OTHER_OWNER = uuid.UUID(int=2)


@dataclass
class _FakeTemplateRepo:
    rows: dict[uuid.UUID, TemplateView] = field(default_factory=dict)
    owners: dict[uuid.UUID, uuid.UUID] = field(default_factory=dict)
    flushed: int = 0

    async def create(self, owner_id: uuid.UUID, data: TemplateCreate) -> TemplateView:
        view = TemplateView(
            id=uuid.uuid4(),
            title=data.title,
            body=data.body,
            category=data.category,
            tool_key=data.tool_key,
        )
        self.rows[view.id] = view
        self.owners[view.id] = owner_id
        self.flushed += 1
        return view

    async def list_for_owner(self, owner_id: uuid.UUID) -> list[TemplateView]:
        return [v for tid, v in self.rows.items() if self.owners[tid] == owner_id]

    async def delete(self, owner_id: uuid.UUID, template_id: uuid.UUID) -> bool:
        if self.rows.get(template_id) is None or self.owners.get(template_id) != owner_id:
            return False
        del self.rows[template_id]
        del self.owners[template_id]
        self.flushed += 1
        return True


@pytest.mark.asyncio
async def test_create_then_list_returns_view() -> None:
    repo: TemplateRepo = _FakeTemplateRepo()

    view = await repo.create(
        OWNER, TemplateCreate(title="爽文开局", body="主角穿越...", category=None, tool_key=None)
    )
    listed = await repo.list_for_owner(OWNER)

    assert view.title == "爽文开局"
    assert view.body == "主角穿越..."
    assert [v.id for v in listed] == [view.id]


@pytest.mark.asyncio
async def test_list_filters_by_owner() -> None:
    repo: TemplateRepo = _FakeTemplateRepo()
    await repo.create(OWNER, TemplateCreate(title="a", body="b"))

    assert await repo.list_for_owner(OTHER_OWNER) == []


@pytest.mark.asyncio
async def test_delete_existing_returns_true() -> None:
    repo: TemplateRepo = _FakeTemplateRepo()
    view = await repo.create(OWNER, TemplateCreate(title="a", body="b"))

    deleted = await repo.delete(OWNER, view.id)

    assert deleted is True
    assert await repo.list_for_owner(OWNER) == []


@pytest.mark.asyncio
async def test_delete_missing_returns_false() -> None:
    repo: TemplateRepo = _FakeTemplateRepo()

    assert await repo.delete(OWNER, uuid.uuid4()) is False


@pytest.mark.asyncio
async def test_delete_other_owner_returns_false() -> None:
    repo: TemplateRepo = _FakeTemplateRepo()
    view = await repo.create(OWNER, TemplateCreate(title="a", body="b"))

    assert await repo.delete(OTHER_OWNER, view.id) is False


def test_template_view_is_frozen() -> None:
    view = TemplateView(id=uuid.uuid4(), title="a", body="b", category=None, tool_key=None)
    with pytest.raises(ValidationError):
        view.title = "x"
