#!/usr/bin/env python3
"""후보 선택 VLM 을 바꾸면 「전부 부적합」을 말하는가 — 같은 4장, 모델만 교체.

무엇이 문제였나 — 「한국의 현대 골목길 사거리」를 조사했는데 내려받은 후보
4장이 **전부 사거리가 아니었다**(일직선 골목·오르막 골목·막다른 골목).
그런데 선택 VLM 이 2번을 고르고 이유를 이렇게 적었다:

    후보 중 유일하게 현대 한국 골목길의 **교차 지점**을 실제 생활 환경 속에서
    식별할 수 있어 사거리 참고 자료로 가장 적합하다.

**없는 것을 있다고 봤다.** 「전부 부적합」 갈래는 이미 있다 — 스키마의
`chosen_index` 가 `minimum: 0` 이고 코드가 `1 <= chosen <= len` 이 아니면
`None`(사용 가능 후보 없음)으로 떨어뜨린다. 갈래가 없는 게 아니라 **기준을
느슨하게 적용**한 것이다.

이 도구는 **같은 후보 4장·같은 프롬프트·같은 스키마**에 모델만 바꿔 넣는다.
그러면 「모델을 바꾸면 되는 일인가, 프롬프트를 고쳐야 하는 일인가」가 갈린다.

★프로덕션 경로를 그대로 쓴다 — `pick_system` 팩 · `build_pick_user_head` ·
 `build_pick_schema` · `call_structured`. 다시 짜지 않는다(측정 도구가
 프로덕션과 다르면 무엇을 쟀는지 알 수 없다).

usage:
  probe_era_pick_model.py                        # gemini-pro (기본)
  probe_era_pick_model.py --model gpt            # 현행과 대조
  probe_era_pick_model.py --rounds 3             # 흔들림까지
  probe_era_pick_model.py --subject "…"          # 다른 조사 대상
"""
import argparse
import json
import sys
from pathlib import Path

sys.path.insert(0, "/Users/manta/Documents/Projects/TheRoad-I1/scratchpad")
import _opik_env  # noqa: E402,F401  ★cwd 를 backend 로 고정

ROOT = Path("/Users/manta/Documents/Projects/TheRoad-I1")
RECIPE = (ROOT / "projects/da049582-2c6d-492c-979d-f468d61bab6e/images"
          "/fb7a883f-baac-4145-9131-732ce628d474/scene/recipe")
DEFAULT_HASH = "ae2d4d155c10d3e3"   # 「한국의 현대 골목길 사거리」


def main() -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--model", default="gemini-pro",
                    help="선택 모델 별칭 (기본 gemini-pro = Gemini 3.1 Pro)")
    ap.add_argument("--rounds", type=int, default=1)
    ap.add_argument("--hash", default=DEFAULT_HASH,
                    help="어느 조사의 후보를 쓸지 (records 의 era_ref:: 해시)")
    ap.add_argument("--subject", default="",
                    help="조사 대상 문안 — 비우면 records 기록을 쓴다")
    args = ap.parse_args()

    recs = json.loads((RECIPE / "records.json").read_text(encoding="utf-8"))
    rec = recs.get(f"era_ref::{args.hash}") or {}
    subject = args.subject or rec.get("subject", "")
    cand_dir = RECIPE / f".eraref_{args.hash}_cand"
    cands = sorted(cand_dir.glob("cand*.png"))
    if not (subject and cands):
        print(f"★재료가 없다 — subject={subject!r} 후보={len(cands)}")
        return 1

    print(f"조사 대상 : {subject}")
    print(f"후보      : {len(cands)}장 {[p.name for p in cands]}")
    print(f"현행 기록 : picked_index={rec.get('picked_index')} "
          f"— {rec.get('picked_reason_ko','')[:70]}")
    print(f"이번 모델 : {args.model}\n")

    # ── 프로덕션과 같은 조립 (era_research.py:209-228) ──────────────
    from app.modules.llm.llm_client import call_structured
    from app.modules.pipeline.multiroll_gemini import png_part
    from app.modules.pipeline.search_grounded_ref import (
        build_pick_schema, build_pick_user_head, resolve_ref_pack_version,
    )
    from app.modules.prompt_loader import load_prompt

    world = ""   # 이 프로브는 세계 사실 없이 — 현행 호출과 같은 자리를 재현할
    #              때는 records 에 남지 않아 비운다(양쪽 arm 에 동일).
    pick_sys = load_prompt("search_grounded_ref", "pick_system",
                           version=resolve_ref_pack_version()).strip()
    parts = [{"type": "text",
              "text": build_pick_user_head(structure_desc=subject,
                                           world_facts_block=world)}]
    for i, p in enumerate(cands, 1):
        parts.append({"type": "text", "text": f"PHOTOGRAPH {i}:"})
        parts.append(png_part(p))

    tag = "era_pick_probe"
    pc = {tag: {"model": args.model}}
    schema = build_pick_schema(max_items=len(cands))

    for r in range(1, args.rounds + 1):
        try:
            v = call_structured(tag, pick_sys, parts, schema,
                                project_config=pc, schema_name=tag)
        except Exception as exc:  # noqa: BLE001
            print(f"  {r}회차 ✘ {type(exc).__name__}: {exc}")
            continue
        chosen = int(v.get("chosen_index") or 0)
        mark = "★전부 부적합" if chosen == 0 else f"{chosen}번 선택"
        print(f"  {r}회차 → {mark}")
        print(f"      이유: {str(v.get('chosen_reason_ko',''))[:160]}")
        for d in (v.get("verdicts") or []):
            print(f"      후보{d.get('index')} usable={d.get('usable')} "
                  f"score={d.get('score')} — {str(d.get('reason_ko',''))[:90]}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
