"""EscalationEnvelope — 4B → 26B 핸드오프 계약.

4B 가 "자신이 처리 못한다" 고 판단했을 때 26B 에게 전달하는 구조화 메시지.
26B 는 distilled_context 로 방향을 잡고 original_pointers 로 필요한 원문만 재조회.

PR-A 는 dataclass 계약만 정의. 실제 생성/소비는 PR-B 의 escalation_service 가 담당.
"""

from __future__ import annotations

import json
from dataclasses import asdict, dataclass, field
from typing import Any


ValidFromStage = {
    "triage",
    "classify",
    "summarize_short",
    "advice_trigger",
    "night_sweep",
    "ask_pre",
    "unknown",  # 호환성용
}


@dataclass(frozen=True)
class EscalationEnvelope:
    from_stage: str
    escalation_reasons: tuple[str, ...]
    risk_flags: tuple[str, ...]
    distilled_context: str
    original_pointers: dict[str, Any] = field(default_factory=dict)
    synthesis_directives: tuple[str, ...] = ()
    user_intent: str | None = None
    draft_hint: str | None = None

    def __post_init__(self) -> None:
        if self.from_stage not in ValidFromStage:
            raise ValueError(
                f"from_stage '{self.from_stage}' not in {ValidFromStage}"
            )
        if not isinstance(self.escalation_reasons, tuple):
            raise TypeError("escalation_reasons must be tuple (for hashability)")
        if not isinstance(self.risk_flags, tuple):
            raise TypeError("risk_flags must be tuple (for hashability)")
        if not isinstance(self.synthesis_directives, tuple):
            raise TypeError("synthesis_directives must be tuple (for hashability)")

    # -- 26B system prompt 주입용 텍스트 -----------------------------------
    def to_system_injection(self) -> str:
        lines = [
            "=== ESCALATION ENVELOPE (from 4B) ===",
            f"from_stage: {self.from_stage}",
            f"reasons: {', '.join(self.escalation_reasons) or '(none)'}",
            f"risk_flags: {', '.join(self.risk_flags) or '(none)'}",
        ]
        if self.user_intent:
            lines.append(f"user_intent: {self.user_intent}")
        if self.draft_hint:
            lines.append(f"draft_hint: {self.draft_hint}")

        if self.synthesis_directives:
            lines.append("")
            lines.append("synthesis_directives (각 risk_flag 별 지시사항, 반드시 준수):")
            for d in self.synthesis_directives:
                lines.append(f"  - {d}")

        if self.distilled_context:
            lines.append("")
            lines.append("distilled_context (4B 가 압축한 요지 — 참고용, 숫자·인용은 원문 재확인 필수):")
            lines.append(self.distilled_context)

        if self.original_pointers:
            lines.append("")
            lines.append("original_pointers (필요 시 재조회):")
            lines.append(json.dumps(self.original_pointers, ensure_ascii=False, indent=2))

        return "\n".join(lines)

    # -- JSON round-trip ---------------------------------------------------
    def to_json(self) -> str:
        return json.dumps(asdict(self), ensure_ascii=False)

    @classmethod
    def from_json(cls, s: str) -> EscalationEnvelope:
        raw = json.loads(s)
        return cls(
            from_stage=raw["from_stage"],
            escalation_reasons=tuple(raw.get("escalation_reasons", ())),
            risk_flags=tuple(raw.get("risk_flags", ())),
            distilled_context=raw.get("distilled_context", ""),
            original_pointers=raw.get("original_pointers", {}) or {},
            synthesis_directives=tuple(raw.get("synthesis_directives", ())),
            user_intent=raw.get("user_intent"),
            draft_hint=raw.get("draft_hint"),
        )
