"""Opus pilot 결과를 production 스틸로 반영한다.

Opus 가 254샷을 원본 롤부터 다시 골랐고(116샷이 기존과 다른 롤), 심각하다고
판정한 8샷만 i2i 로 고쳤다. 그 결과가 `_final.png` 다. 여기서 하는 일은
그것을 정본인 `_sel.png` 자리에 놓는 것뿐이다.

되돌릴 수 있게 현재 `_sel.png` 를 먼저 백업한다. 원본 롤(`_a/_b/_c`)과 어제의
`_fix.png` 는 손대지 않으므로 어느 시점으로든 돌아갈 수 있다.
"""
from __future__ import annotations

import json
import shutil
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
PILOT = ROOT / "artifact/20260806_opus_pilot"
RECIPE = (ROOT / "projects/e716bafb-24bb-42b7-aea0-fdb383844ee8/images"
          "/d6a9aa85-b75e-400c-980c-4ee7e876a15b/scene/recipe")
BACKUP = PILOT / "backup_sel"


def main() -> None:
    dry = "--apply" not in sys.argv
    # 이중(Opus+Sol) 결과가 정본이다. 단독 `full.json` 은 1시간 반 앞선 예비
    # 실행이고 12샷이 오류로 비어 있다 — 그 목록을 쓰면 그만큼 반영이 빠진다.
    res = json.loads((PILOT / "full_dual.json").read_text("utf-8"))
    res = res.get("results", res)
    BACKUP.mkdir(parents=True, exist_ok=True)

    applied = same = skipped = 0
    repaired: list[str] = []
    for stem, v in sorted(res.items()):
        if not isinstance(v, dict) or not v.get("final"):
            skipped += 1
            continue
        src, dst = PILOT / "images" / f"{stem}_final.png", RECIPE / f"{stem}_sel.png"
        if not src.exists():
            print(f"  없음: {src.name}")
            skipped += 1
            continue
        if dst.exists() and dst.read_bytes() == src.read_bytes():
            same += 1
            continue
        if not dry:
            if dst.exists():
                shutil.copy2(dst, BACKUP / dst.name)
            shutil.copy2(src, dst)
        applied += 1
        if v.get("final_is_repaired"):
            repaired.append(stem)

    print(f"{'[미리보기] ' if dry else ''}교체 {applied} / 이미 동일 {same} "
          f"/ 건너뜀 {skipped}")
    print(f"  그 중 i2i 수정본 : {len(repaired)}  {repaired}")
    if dry:
        print("\n실제 반영: --apply")
    else:
        print(f"  백업: {BACKUP}")


if __name__ == "__main__":
    main()
