"""Creation gates used before and during deep decode."""
from __future__ import annotations

import json
from typing import Any, Callable

from core.llm import chat_json as default_chat_json
from core.prompts import load_prompt
from core.text_limits import DIRECTIVE_CONTEXT_MAX_CHARS, clip_text
from decode_content.models import GateResult


GATE_ADMIT = load_prompt("gate_admit")
GATE_REFUTE = load_prompt("gate_refute")
GATE_TIEBREAK = load_prompt("gate_tiebreak")
GATE_HOW_ADMIT = load_prompt("gate_how_admit")
GATE_HOW_REFUTE = load_prompt("gate_how_refute")
GATE_HOW_TIEBREAK = load_prompt("gate_how_tiebreak")
GATE_WHY_REFUTE = load_prompt("gate_why_refute")

ChatJsonFn = Callable[..., dict[str, Any]]


def vote_bool(
    system: str,
    user: str,
    key: str,
    *,
    on_fail: bool,
    chat_json_fn: ChatJsonFn = default_chat_json,
    timeout: int = 90,
) -> bool:
    try:
        return bool(chat_json_fn(system, user, timeout=timeout).get(key))
    except Exception:
        return on_fail


def creation_gate(read_text: str, *, chat_json_fn: ChatJsonFn = default_chat_json) -> GateResult:
    """Decide whether the read content is reusable creation knowledge."""

    v_admit = vote_bool(GATE_ADMIT, read_text, "in_scope", on_fail=True, chat_json_fn=chat_json_fn)
    v_refute = not vote_bool(GATE_REFUTE, read_text, "out_of_scope", on_fail=False, chat_json_fn=chat_json_fn)
    if v_admit == v_refute:
        return GateResult(
            passed=v_admit,
            reason=f"admit={v_admit}/refute={v_refute} 一致",
            details={"admit": v_admit, "refute": v_refute},
        )
    v_tie = vote_bool(GATE_TIEBREAK, read_text, "in_scope", on_fail=False, chat_json_fn=chat_json_fn)
    return GateResult(
        passed=v_tie,
        reason=f"admit={v_admit}/refute={v_refute} 分歧→裁决={v_tie}",
        details={"admit": v_admit, "refute": v_refute, "tiebreak": v_tie},
    )


def chain_signals(steps: list[dict[str, Any]]) -> list[str]:
    sigs: list[str] = []
    outs = [(s.get("output") or "") for s in steps]
    independent_count = 0
    for idx, step in enumerate(steps):
        if idx == 0:
            continue
        step_input = step.get("input") or ""
        if not (("←" in step_input) or any(o and o[:4] in step_input for o in outs[:idx])):
            independent_count += 1
    if independent_count >= 2:
        sigs.append(f"{independent_count} 个后步的 input 未指向前步产出（各自起头）")
    for i in range(len(outs)):
        for j in range(i + 1, len(outs)):
            left, right = outs[i], outs[j]
            if left and right and (left in right or right in left):
                sigs.append(f"步骤{i + 1}与{j + 1}产出近义（{left} / {right}）")
                break
    return sigs


def how_gate(knowledge: dict[str, Any], *, chat_json_fn: ChatJsonFn = default_chat_json) -> GateResult:
    payload = json.dumps(
        {
            "purpose": knowledge.get("purpose"),
            "steps": [
                {
                    "input": step.get("input"),
                    "方法": clip_text(step.get("directive") or "", DIRECTIVE_CONTEXT_MAX_CHARS),
                    "产出": step.get("output"),
                }
                for step in knowledge.get("steps", [])
            ],
            "代码信号": chain_signals(knowledge.get("steps", [])),
        },
        ensure_ascii=False,
    )
    v_admit = vote_bool(GATE_HOW_ADMIT, payload, "is_real_how", on_fail=True, chat_json_fn=chat_json_fn)
    v_refute = not vote_bool(GATE_HOW_REFUTE, payload, "is_fake", on_fail=False, chat_json_fn=chat_json_fn)
    if v_admit == v_refute:
        return GateResult(
            passed=v_admit,
            reason=f"admit={v_admit}/refute={v_refute} 一致",
            details={"admit": v_admit, "refute": v_refute},
        )
    v_tie = vote_bool(GATE_HOW_TIEBREAK, payload, "is_real_how", on_fail=False, chat_json_fn=chat_json_fn)
    return GateResult(
        passed=v_tie,
        reason=f"admit={v_admit}/refute={v_refute} 分歧→裁决={v_tie}",
        details={"admit": v_admit, "refute": v_refute, "tiebreak": v_tie},
    )


def why_refute_gate(knowledge: dict[str, Any], *, chat_json_fn: ChatJsonFn = default_chat_json) -> GateResult:
    payload = json.dumps({"阐述": knowledge.get("阐述")}, ensure_ascii=False)
    try:
        result = chat_json_fn(GATE_WHY_REFUTE, payload, timeout=90)
    except Exception:
        return GateResult(passed=True, reason="API错误→保留", details={"not_why": False})
    not_why = bool(result.get("not_why"))
    verdict = str(result.get("verdict") or "")
    reason = str(result.get("reason") or "")
    return GateResult(
        passed=not not_why,
        reason=reason,
        details={"not_why": not_why, "verdict": verdict},
    )
