"""防污染防火墙 — guest 门禁 · subject 写保护 · turn 策略。"""

from __future__ import annotations

from typing import Any

from niannian.memory.meta import parse_atom_meta

F9_STRONG_ANCHORS = frozenset({"device_observation", "pinn_confirmed", "multi_source"})


class FirewallViolation(Exception):
    def __init__(self, violations: list[str]) -> None:
        self.violations = list(violations)
        super().__init__(", ".join(violations))


def validate_atom_meta(meta: dict[str, Any]) -> tuple[bool, list[str]]:
    """F8/F9 硬规则。返回 (ok, violations)。"""
    parsed = parse_atom_meta(meta)
    violations: list[str] = []

    if parsed.provenance.trust_tier == "guest_reference" and parsed.subject_eligible:
        violations.append("guest_reference_forbidden")

    if parsed.memory_scope == "object" and parsed.subject_eligible:
        violations.append("object_scope_subject_eligible_forbidden")

    if parsed.subject_eligible:
        anchor = parsed.provenance.reality_anchor
        tier = parsed.provenance.trust_tier
        if anchor == "marked_hypothesis":
            violations.append("marked_hypothesis_not_subject_eligible")
        if tier in ("web", "user_paste") and not anchor:
            violations.append("reality_anchor_required")

    return len(violations) == 0, violations


def check_f9_sl_adopt(meta: dict[str, Any] | None) -> bool:
    """F9：web/user_paste 无强 anchor 不得进入 SL 进化（SL4/SL5）。"""
    parsed = parse_atom_meta(meta)
    tier = parsed.provenance.trust_tier
    if tier not in ("web", "user_paste"):
        return True
    anchor = parsed.provenance.reality_anchor
    return bool(anchor and anchor in F9_STRONG_ANCHORS)


def f9_pending_verification(meta: dict[str, Any] | None) -> bool:
    """弱 anchor / 缺 anchor 的 web/user_paste — SL4 候选须标待验证。"""
    parsed = parse_atom_meta(meta)
    tier = parsed.provenance.trust_tier
    if tier not in ("web", "user_paste"):
        return False
    anchor = parsed.provenance.reality_anchor
    if not anchor or anchor == "marked_hypothesis":
        return True
    return anchor not in F9_STRONG_ANCHORS


def assert_subject_write_allowed(meta: dict[str, Any] | None) -> None:
    """F1：客体 / guest 不得写 subject 路径。"""
    if not meta:
        return
    ok, violations = validate_atom_meta(meta)
    if not ok:
        raise FirewallViolation(violations)
    parsed = parse_atom_meta(meta)
    if parsed.memory_scope == "object":
        raise FirewallViolation(["object_scope_forbidden_subject_write"])


def guest_reference_disclaimer() -> str:
    return "（客体/guest·仅供参考·不得参与主体三观与 SL 进化）"


def is_object_turn(session_meta: dict[str, Any] | None) -> bool:
    session = session_meta or {}
    oid = session.get("current_object_id")
    return oid is not None and str(oid).strip() != ""


def should_update_subject_emotion(session_meta: dict[str, Any] | None) -> bool:
    """F3：客体轮次不更新 SL2 mood；VP 试讲不写 subject。"""
    session = session_meta or {}
    if session.get("trial") is True:
        return False
    return not is_object_turn(session_meta)


def is_subject_summary(key: str, item: dict[str, Any]) -> bool:
    if key.startswith("object:"):
        return False
    return item.get("memory_scope") != "object"


def firewall_trace_line(msg: str) -> str:
    return f"[firewall] {msg}"
