"""실내 pose 가이드 default-deny judge 평가 (Wave5).

outdoor `_evaluate_shared_model_guide_judge` 패턴 차용·indoor 전용 분리.
VLM 호출은 provider(DI judge_fn)에서, 본 모듈은 verdict → attach gate 결정론 평가만.
"""
from typing import Any, Optional, Tuple


def has_grounded_evidence(evidence: Any) -> bool:
    """evidence-backed 가드 (outdoor 기보유) — 배열 non-empty 만으론 부족.

    최소 1개 항목이 dict 이고 shot_key/source_field/quote **모두 strip non-empty**
    여야 근거 있음. 빈 문자열로 채운 object 는 LLM 현실적 실패 모드 → deny.
    """
    if not isinstance(evidence, list):
        return False
    for e in evidence:
        if (isinstance(e, dict)
                and str(e.get("shot_key") or "").strip()
                and str(e.get("source_field") or "").strip()
                and str(e.get("quote") or "").strip()):
            return True
    return False


def evaluate_indoor_pose_guide_judge(verdict: Any) -> Tuple[bool, Optional[str]]:
    """default-deny route judge 평가(group-level) → (attach, deny_reason).

    attach = needs_indoor_pose_guide True + decision_type∈{cross_shot_continuity,
    single_shot_complexity, both} + confidence∈{medium, high} + 근거 있는 evidence.
    no_guide/저신뢰/근거없음·빈근거/판정실패 = no attach(diagnostic).

    ★사용자 결정(2026-06-30) — single_shot_pose_grounding lane 추가: canary 14_5 처럼
    단일 샷의 지지면/접촉 grounding 위험도 admit. 단 group-level 게이트만 여기서 결정하고,
    **어느 샷에 guide 를 붙일지(shot-scoping)는 context 루프가 target_shot_keys +
    figure_count 로 좁힌다**(Codex B': 0-figure establishing/insert 는 절대 target 불가).
    """
    if not isinstance(verdict, dict) or not verdict:
        return False, "judge_failed"
    if not verdict.get("needs_indoor_pose_guide"):
        return False, "judge_no_need"
    if verdict.get("decision_type") not in (
        "cross_shot_continuity", "single_shot_complexity", "both",
    ):
        return False, "judge_no_guide_decision"
    if verdict.get("confidence") not in ("medium", "high"):
        return False, "judge_low_confidence"
    if not has_grounded_evidence(verdict.get("evidence")):
        return False, "judge_missing_evidence"
    return True, None


def resolve_single_shot_targets(verdict: Any) -> set:
    """single_shot lane 의 target_shot_keys → {(si, shi)} 파싱 (구조키, 의미판정 0).

    verdict["target_shot_keys"] = ["14_5", ...] 형식. "si_shi" 만 허용, 그 외 무시.
    context 루프가 이 집합 ∩ (member ∧ figure>=1 ∧ live) 으로 최종 target 확정한다.
    """
    out: set = set()
    if not isinstance(verdict, dict):
        return out
    for tk in (verdict.get("target_shot_keys") or []):
        parts = str(tk).split("_")
        if len(parts) == 2 and parts[0].lstrip("-").isdigit() and parts[1].lstrip("-").isdigit():
            out.add((int(parts[0]), int(parts[1])))
    return out
