"""Scope B 竞品快赢 · 4 个生成器的 spec/schema 契约测试。

校验每个 spec 的 name/tier/reads/writes/output_schema/scope/input_schema，
对齐不变量 #2（只声明 tier）/ #3（续写/扩写/降AI 纯预览 writes=[]；拆书 F1 落库 rules）。
不联网、无 DB。
"""

from __future__ import annotations

import pytest
from ww_agents import (
    AgentSpec,
    BookTeardownResult,
    ContinuationResult,
    DeAiResult,
    PolishResult,
    continue_spec,
    de_ai_spec,
    expand_spec,
    teardown_spec,
)

# (spec, name, tier, reads, writes, output_schema)
_COMPETITOR_SPECS = [
    (
        continue_spec,
        "continue",
        "writer",
        ["projects", "outline", "chapters"],
        [],
        ContinuationResult,
    ),
    (expand_spec, "expand", "writer", ["projects"], [], PolishResult),
    (de_ai_spec, "de-ai", "analyst", ["projects"], [], DeAiResult),
    # F1：拆书结论可落库为项目 rules（writes=["rules"]；其余三者仍纯预览）。
    (teardown_spec, "teardown", "analyst", ["projects"], ["rules"], BookTeardownResult),
]


@pytest.mark.parametrize(
    ("spec", "name", "tier", "reads", "writes", "output_schema"),
    _COMPETITOR_SPECS,
)
def test_competitor_spec_declares_expected_contract(
    spec: AgentSpec,
    name: str,
    tier: str,
    reads: list[str],
    writes: list[str],
    output_schema: type,
) -> None:
    assert spec.name == name
    assert spec.tier == tier
    assert list(spec.reads) == reads
    assert list(spec.writes) == writes  # 不变量 #3：续写/扩写/降AI 纯预览；拆书落 rules
    assert spec.output_schema is output_schema
    assert spec.scope == "builtin"
    assert spec.input_schema is None  # 注入材料为序列化文本，非结构化入参


@pytest.mark.parametrize("spec", [row[0] for row in _COMPETITOR_SPECS])
def test_competitor_spec_has_nonempty_system_prompt(spec: AgentSpec) -> None:
    assert spec.system_prompt.strip()


# ---- schema 解析/默认值契约 ----


def test_continuation_result_parses_text() -> None:
    parsed = ContinuationResult.model_validate({"text": "雷光再起，他迈步向前。"})
    assert parsed.text == "雷光再起，他迈步向前。"


def test_polish_result_parses_text() -> None:
    parsed = PolishResult.model_validate({"text": "夜色更浓，风穿过断壁。"})
    assert parsed.text == "夜色更浓，风穿过断壁。"


def test_de_ai_result_parses_text() -> None:
    parsed = DeAiResult.model_validate({"text": "他咧嘴一笑，没多说什么。"})
    assert parsed.text == "他咧嘴一笑，没多说什么。"


def test_book_teardown_result_parses_and_lists_default_empty() -> None:
    empty = BookTeardownResult(structure="开篇立钩→铺垫→爆发")
    assert empty.themes == []
    assert empty.archetypes == []
    assert empty.hooks == []
    parsed = BookTeardownResult.model_validate(
        {
            "themes": ["逆袭", "复仇"],
            "archetypes": ["废柴主角", "腹黑反派"],
            "structure": "黄金三章立爽点，逐卷升级",
            "hooks": ["章末反转", "扮猪吃虎"],
        }
    )
    assert parsed.themes == ["逆袭", "复仇"]
    assert parsed.structure == "黄金三章立爽点，逐卷升级"
    assert parsed.hooks == ["章末反转", "扮猪吃虎"]
