#!/usr/bin/env python3
"""출력이 프롬프트 규칙을 어겼는지 기계로 잰다 — 어길 수 있게 못박힌 것만.

★낱말 빈도로 프롬프트를 세면 인상만 남는다(실제로 ②③ 진단이 그렇게
빗나갔다). 어긴 것이 보이는 규칙만 고른다:

  R1 샷타입 낱말이 t2i_prompt 에      (v43 이 고친 것 — 재발 감시)
  R2 ID 정책 위반                      (policy 별 허용 형태가 명문)
  R3 실 수치                           (「실 수치 금지, 상대 비율만」)
  R4 원문에 없는 사실                  (조명 상태 등 — 후보만, 판정은 사람)
  R5 t2i_prompt 길이                   (「한 컷 = 한 문장」 원칙)
"""
import json
import re
import sys

sys.path.insert(0, "/Users/manta/Documents/Projects/TheRoad-I1/scratchpad")
from _opik_env import opik_target  # ★cwd 를 backend 로 고정 + 미로드 시 중단
from tools.opik_prompt_audit.audit.fetch import fetch_spans
from app.core.config import settings

BASE, WS, PROJ = opik_target()
spans = fetch_spans(BASE, getattr(settings, "opik_workspace", None) or "default",
                    getattr(settings, "opik_project_name", None) or "theroad",
                    "2026-08-24T13:00:00", "2026-08-24T16:10:00")
sd = [s for s in spans if "op:scene_detail" in (s.get("tags") or [])]

R1 = re.compile(r"\b(close-?up|wide shot|medium shot|long shot|wide view|"
                r"establishing shot|full shot)\b", re.I)
R3 = re.compile(r"\b\d+\s?(cm|mm|m|meters?|centimet\w*|inch\w*|feet|ft)\b", re.I)
# 원문(정리본)에 없는 조명 상태 — 후보 탐지
# ★2026-08-25: `switched off` 만 잡던 정규식이 재실행에서 `goes out` ·
#   `blackout` 을 놓쳤다. 같은 왜곡이 다른 말로 남았는데 「1/6 → 1/6」 이라
#   변화 없음으로 읽힐 뻔했다 — 덜 잡는 자로 재면 0 이 「없다」가 된다.
R4 = re.compile(r"(lights?\s+(?:are\s+)?(?:off|out)|goes?\s+out|went\s+out|"
                r"gone\s+dark|black-?out|power\s+cut|power\s+fail\w*|"
                r"switched?\s+off|turned?\s+off|cuts?\s+out|unlit|"
                r"darkness|pitch\s+dark|extinguish\w*|momentary\s+dark\w*)", re.I)

cards = []
for s in sd:
    try:
        cards.append(json.loads(
            s["output"]["choices"][0]["message"]["content"]))
    except Exception:
        pass

print(f"카드 {len(cards)}장\n")
rows = []
for c in cards:
    si = c.get("scene_index")
    for v in c.get("t2i_variations") or []:
        p = v.get("t2i_prompt") or ""
        rows.append({
            "scene": si, "label": v.get("variant_label"),
            "len": len(p),
            "R1": R1.findall(p),
            "R3": R3.findall(p),
            "R4": R4.findall(p),
            "ids": sorted(set(re.findall(r"\bC\d{2}(?:O\d{2})?\b", p))),
            "prompt": p,
        })

def show(key, title):
    hit = [r for r in rows if r[key]]
    print(f"── {title}: {len(hit)}/{len(rows)}")
    for r in hit:
        print(f"    씬{r['scene']} {r['label']}: {r[key]}")

show("R1", "R1 샷타입 낱말")
show("R3", "R3 실 수치")
show("R4", "R4 조명 꺼짐 표현 (원문 대조 필요)")

print(f"\n── R5 t2i_prompt 길이")
for r in sorted(rows, key=lambda x: -x["len"]):
    print(f"    {r['len']:>5}자  씬{r['scene']} {r['label']}  "
          f"ID {','.join(r['ids']) or '없음'}")
avg = sum(r['len'] for r in rows) // len(rows) if rows else 0
print(f"    평균 {avg:,}자")
