"""Prompt 外置（方案A）集成回归 —— 设计 §6 #12 / #15。

#12 编排器无回归：review / generation / outline / style_extract 节点据内置 `SPECS`
spec 构请求（mock gateway，不触真 LLM），断言进缓存断点前块的 `system` 文本
== 旧行为（即 `load_prompt(name)` / `SPECS[name].system_prompt`）——证明 prompt
外迁到 `.md` 后字节级零变化（不变量 #9）。

#15 import-smoke：`from ww_agents import AgentSpec/outliner_spec/refiner_spec/
style_extract_spec/continuity_spec` 不抛，且拿到的对象 `is SPECS[name]`（同一实例）
——证明 apps/api 路由 + 编排器（本波仍用 `*_spec`）的 import 路径未破。
"""

from __future__ import annotations

import uuid

from ww_agents import (
    SPECS,
    AgentSpec,
    continuity_spec,
    load_prompt,
    outliner_spec,
    refiner_spec,
    style_extract_spec,
)
from ww_core.orchestrator.generation_node import _build_request
from ww_core.orchestrator.outline_node import build_outline_request
from ww_core.orchestrator.review_node import build_review_request
from ww_core.orchestrator.state import ChapterState
from ww_core.orchestrator.style_extract_node import build_style_extract_request

_USER_ID = uuid.UUID("00000000-0000-0000-0000-000000000001")
_PROJECT_ID = uuid.UUID("00000000-0000-0000-0000-000000000002")


def _system_text(spec: AgentSpec, req_system: list) -> str:
    """从 LlmRequest.system 取唯一的缓存断点前块文本（不变量 #9）。"""
    assert len(req_system) == 1, "system 应只有一个稳定块（缓存断点前）"
    block = req_system[0]
    assert block.cache is True, "system 稳定块须标 cache=True（缓存断点前块）"
    return block.text


# ---- #12 编排器无回归：四节点 system 文本 == load_prompt(name) ----


def test_review_node_system_block_equals_load_prompt() -> None:
    # Arrange — 用 continuity（四审之一）构造审稿 state
    state: ChapterState = {  # type: ignore[typeddict-item]
        "review_context": "## 审稿材料\n世界观硬规则……\n## 待审本章草稿\n正文……",
        "user_id": _USER_ID,
        "project_id": _PROJECT_ID,
    }
    # Act
    req = build_review_request(continuity_spec, state)
    # Assert — system 块文本 == 外置 .md 的运行时值，且 == spec.system_prompt（同一真相源）
    assert _system_text(continuity_spec, req.system) == load_prompt("continuity")
    assert _system_text(continuity_spec, req.system) == continuity_spec.system_prompt


def test_generation_node_system_block_equals_load_prompt() -> None:
    # Arrange — worldbuilder 走通用 _build_request（与 character-gen 共用）
    spec = SPECS["worldbuilder"]
    # Act
    req = _build_request(
        spec, context="## 世界观需求\n灵气复苏", user_id=_USER_ID, project_id=_PROJECT_ID
    )
    # Assert
    assert _system_text(spec, req.system) == load_prompt("worldbuilder")
    assert _system_text(spec, req.system) == spec.system_prompt


def test_outline_node_system_block_equals_load_prompt() -> None:
    # Act
    req = build_outline_request(
        outliner_spec, context="## 设定\n……", user_id=_USER_ID, project_id=_PROJECT_ID
    )
    # Assert
    assert _system_text(outliner_spec, req.system) == load_prompt("outliner")
    assert _system_text(outliner_spec, req.system) == outliner_spec.system_prompt


def test_style_extract_node_system_block_equals_load_prompt() -> None:
    # Act
    req = build_style_extract_request(
        style_extract_spec,
        samples_text="样本正文一\n样本正文二",
        user_id=_USER_ID,
        project_id=_PROJECT_ID,
    )
    # Assert
    assert _system_text(style_extract_spec, req.system) == load_prompt("style_extract")
    assert _system_text(style_extract_spec, req.system) == style_extract_spec.system_prompt


def test_review_request_passes_tier_and_schema_unchanged() -> None:
    # 不变量 #2：节点只透传 spec.tier，绝不写死 model；output_schema 据 spec 派生（无回归）
    state: ChapterState = {  # type: ignore[typeddict-item]
        "review_context": "材料……",
        "user_id": _USER_ID,
        "project_id": _PROJECT_ID,
    }
    req = build_review_request(continuity_spec, state)
    assert req.tier == continuity_spec.tier
    assert req.output_schema is continuity_spec.output_schema


# ---- #15 import-smoke（apps/api + 编排器仍用 *_spec）----


def test_import_smoke_specs_are_same_instance() -> None:
    # 兼容期不变量：模块级 *_spec 与 SPECS[name] 是同一实例（不双真相，设计 §3.4 / #14）
    assert isinstance(AgentSpec, type)
    assert outliner_spec is SPECS["outliner"]
    assert refiner_spec is SPECS["refiner"]
    assert style_extract_spec is SPECS["style_extract"]
    assert continuity_spec is SPECS["continuity"]
