"""판정 팩 내용 지문 — 버전 문자열이 아니라 bytes 가 지문을 움직인다.

2026-08-08 확인: 판정 팩 v7 을 만들고도 최종 스틸 311장 중 253장이
재판정 없이 재사용됐다. 판정·수정 텍스트는 생성 프롬프트에 들어가지
않아서, 버전 '문자열' 스탬프는 셀렉터 상수·해석 코드·서버 메모리 중
어느 층이 낡아도 움직이지 않는다. 로드 대상 디렉토리의 내용 해시가
지문에 접혀야 어느 층이 낡아도 지문이 진실을 따라간다.
"""
import pytest

import app.modules.pipeline.multiroll_gemini as mg
import app.modules.prompt_loader as pl


def test_still_selector_hash_stable_and_16hex():
    a = mg.judge_pack_content_hash(mg.STILL_JUDGE_PACK_VERSION)
    b = mg.judge_pack_content_hash(mg.STILL_JUDGE_PACK_VERSION)
    assert a == b
    assert len(a) == 16
    int(a, 16)  # hex 여야 한다


def test_adjacent_pack_versions_have_different_content():
    # 실제 팩 최근 두 판이 같은 해시면 접는 의미가 없다.
    sels = sorted(mg.JUDGE_PACK_VERSION_MAP, key=int)
    h_prev = mg.judge_pack_content_hash(sels[-2])
    h_last = mg.judge_pack_content_hash(sels[-1])
    assert h_prev != h_last


def test_content_change_moves_hash(tmp_path, monkeypatch):
    # 버전 문자열 층이 전부 낡아도, 팩 bytes 1 byte 변경 = 지문 이동.
    # (#77: 캐시가 prompt_loader 공용 함수로 이관됨 — 거기를 비운다)
    d = tmp_path / "multiroll_judge" / "9.999901010000"
    d.mkdir(parents=True)
    (d / "judge_still.md").write_text("v1", encoding="utf-8")
    monkeypatch.setattr(pl, "PROMPTS_BASE", tmp_path)
    pl.pack_dir_content_hash.cache_clear()
    h1 = mg._pack_dir_content_hash("9.999901010000")
    (d / "judge_still.md").write_text("v2", encoding="utf-8")
    pl.pack_dir_content_hash.cache_clear()
    h2 = mg._pack_dir_content_hash("9.999901010000")
    assert h1 != h2


def test_missing_or_empty_pack_dir_fails_closed(tmp_path, monkeypatch):
    monkeypatch.setattr(pl, "PROMPTS_BASE", tmp_path)
    pl.pack_dir_content_hash.cache_clear()
    with pytest.raises(ValueError):
        mg._pack_dir_content_hash("0.000000000000")
    empty = tmp_path / "multiroll_judge" / "1.000000000000"
    empty.mkdir(parents=True)
    with pytest.raises(ValueError):
        mg._pack_dir_content_hash("1.000000000000")


def test_unknown_selector_fails_closed():
    with pytest.raises(ValueError):
        mg.judge_pack_content_hash("없는셀렉터")


def test_recipe_pack_content_hash_16hex_and_distinct():
    # #77-A: 레시피 팩도 같은 공용 해시 — 실제 팩으로 16 hex, 판정 팩과
    # 다른 내용이니 다른 값이어야 한다.
    from app.modules.pipeline.still_recipe import recipe_pack_content_hash

    h = recipe_pack_content_hash("1")
    assert len(h) == 16
    int(h, 16)
    assert h != mg.judge_pack_content_hash(mg.STILL_JUDGE_PACK_VERSION)


def test_recipe_pack_unknown_selector_fails_closed():
    from app.modules.pipeline.still_recipe import recipe_pack_content_hash

    with pytest.raises(ValueError):
        recipe_pack_content_hash("없는셀렉터")


def test_clear_outputs_keeps_sub_asset_namespace(tmp_path):
    # 지문 mismatch 정리가 롤의 입력(밑줄 둘 하위 자산)을 지우면 안 된다 —
    # 2026-08-08 카나리아 S1sh3: 방금 만든 배경판이 지워져 롤 생성이 죽었다.
    from app.modules.pipeline.multiroll_select import _clear_outputs

    stem = tmp_path / "S1sh3"
    for name in ("S1sh3_a.png", "S1sh3_sel.png", "S1sh3_fix.png",
                 "S1sh3__bgfirst_bg.png"):
        (tmp_path / name).write_bytes(b"x")
    _clear_outputs(stem)
    assert not (tmp_path / "S1sh3_a.png").exists()
    assert not (tmp_path / "S1sh3_sel.png").exists()
    assert not (tmp_path / "S1sh3_fix.png").exists()
    assert (tmp_path / "S1sh3__bgfirst_bg.png").exists()
