"""persist-all acceptance 6종 검증 로직 테스트 (Wave1/2 invariant 락).

scripts/verify_persist_all_acceptance.run_acceptance_checks 가 정상 데이터=PASS,
위반 데이터(경계 깨짐/dangling/dup)=FAIL 로 잡는지 결정론 검증. PG theroad_test.
"""

import json
import uuid
from datetime import datetime, timezone

from app.core.database import SessionLocal
from app.models.catalog import ProjectRegistry, UserAccount
from app.models.project import Episode, ImageAsset
from scripts.verify_persist_all_acceptance import run_acceptance_checks


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _seed_base(db) -> tuple[str, str]:
    uid = str(uuid.uuid4())
    db.add(UserAccount(
        id=uid, username=f"u_{uid[:8]}", display_name="t", password_hash="x",
        role="admin", created_at=_now(), updated_at=_now(),
    ))
    db.commit()
    pid = str(uuid.uuid4())
    db.add(ProjectRegistry(
        id=pid, name="Acceptance", created_by=uid, created_at=_now(), updated_at=_now(),
    ))
    eid = str(uuid.uuid4())
    db.add(Episode(
        id=eid, project_id=pid, episode_number=1, title="P",
        source_filename="p.pdf", source_path="p.pdf", created_at=_now(), updated_at=_now(),
    ))
    db.commit()
    return pid, eid


def _asset(pid, eid, **kw) -> ImageAsset:
    base = dict(
        id=str(uuid.uuid4()), project_id=pid, episode_id=eid,
        asset_type="generated", status="generated", created_at=_now(),
    )
    base.update(kw)
    return ImageAsset(**base)


def _by_name(results):
    return {r.name: r for r in results}


def test_clean_project_all_pass():
    db = SessionLocal()
    try:
        pid, eid = _seed_base(db)
        face = _asset(pid, eid, asset_type="reference", is_intermediate=False,
                      pipeline_role="reference_face", file_path="f/face.png")
        outfit = _asset(pid, eid, asset_type="reference", is_intermediate=False,
                        pipeline_role="reference_outlook", file_path="f/outfit.png")
        db.add(face); db.add(outfit); db.flush()
        comp = _asset(pid, eid, asset_type="reference", is_intermediate=False,
                      pipeline_role="reference_composite", file_path="f/comp.png",
                      input_image_ids=json.dumps([face.id, outfit.id]))
        scene = _asset(pid, eid, asset_type="scene", is_intermediate=False,
                       pipeline_role="scene_still", file_path="f/scene.png")
        db.add(comp); db.add(scene); db.flush()
        variation = _asset(pid, eid, asset_type="scene", is_intermediate=False,
                           pipeline_role="scene_still", file_path="f/var.png",
                           source_image_id=scene.id,
                           input_image_ids=json.dumps([scene.id]))
        rej = _asset(pid, eid, asset_type="generated", is_intermediate=True,
                     pipeline_role="scene_regeneration_candidate", disposition="rejected",
                     file_path="f/rej.png")
        db.add(variation); db.add(rej)
        db.commit()

        results = run_acceptance_checks(db, pid, eid)
        assert all(r.passed for r in results), _by_name(results)
    finally:
        db.close()


def test_violations_caught():
    db = SessionLocal()
    try:
        pid, eid = _seed_base(db)
        # 위반2: 최종물(reference) 인데 is_intermediate=true
        db.add(_asset(pid, eid, asset_type="reference", is_intermediate=True,
                      pipeline_role="reference_face", file_path="v/a.png"))
        # 위반3: intermediate 인데 asset_type<>generated
        db.add(_asset(pid, eid, asset_type="scene", is_intermediate=True,
                      file_path="v/b.png"))
        # 위반1: dangling input_image_ids
        db.add(_asset(pid, eid, asset_type="generated", is_intermediate=True,
                      file_path="v/c.png",
                      input_image_ids=json.dumps(["nonexistent-uuid"])))
        # 위반4: composite 인데 input 1개
        db.add(_asset(pid, eid, asset_type="reference", is_intermediate=False,
                      pipeline_role="reference_composite", file_path="v/d.png",
                      input_image_ids=json.dumps(["nonexistent-uuid"])))
        # 위반6: 같은 file_path 가 intermediate true/false 양쪽
        db.add(_asset(pid, eid, asset_type="scene", is_intermediate=False,
                      file_path="v/dup.png"))
        db.add(_asset(pid, eid, asset_type="generated", is_intermediate=True,
                      file_path="v/dup.png"))
        db.commit()

        by = _by_name(run_acceptance_checks(db, pid, eid))
        assert not by["1_input_image_ids_dangling"].passed
        assert not by["2_final_role_is_intermediate_false"].passed
        assert not by["3_intermediate_asset_type_generated"].passed
        assert not by["4_reference_composite_two_resolved_inputs"].passed
        assert not by["6_no_final_intermediate_file_path_dup"].passed
    finally:
        db.close()
