"""REC-31 (A1) Phase 2: ONE resolver emits a ReferenceBundle from the SHELF; pool never
auto-active; legacy hero/non-hero distinction is preserved; promote round-trips."""
from pathlib import Path
from recoil.core.paths import ProjectPaths
from recoil.core.ref_resolver import resolve_reference_bundle
from recoil.core.ref_stem import subject_stem, ref_filename, subject_id_norm


def _write_png(p: Path):
    p.parent.mkdir(parents=True, exist_ok=True)
    p.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 2048)


def test_subject_stem_hyphenates_multiword():
    assert subject_stem("INT. Lower Decks") == "int-lower-decks"
    assert ref_filename("JADE", "identity", "jpeg") == "jade-identity.jpeg"
    assert subject_id_norm("JADE") == "jade"   # normalizer shared with the gate


def test_resolves_from_shelf_not_legacy(tmp_path):
    pp = ProjectPaths.from_root(tmp_path)
    look = pp.asset_look_dir("char", "jade", "base")
    _write_png(look / ref_filename("jade", "identity", "png"))   # SHELF hero
    _write_png(pp.asset_subject_dir("char", "jade") / "jade_identity_hero_v01.png")  # legacy
    bundle = resolve_reference_bundle(pp, "char", "JADE", "identity")
    ids = bundle.by_role("identity")
    assert ids and ids[0].source == "shelf" and ids[0].is_hero
    assert ids[0].path.name == ref_filename("jade", "identity", "png")


def test_legacy_front_profile_only_yields_no_hero(tmp_path):
    """The WREN disease: legacy front+profile, NO hero file -> bundle resolves
    identity refs but hero_subjects() is EMPTY (is_hero=False on all)."""
    pp = ProjectPaths.from_root(tmp_path)
    d = pp.asset_subject_dir("char", "wren")
    _write_png(d / "wren_identity_front_v01.png")
    _write_png(d / "wren_identity_profile_v01.png")
    bundle = resolve_reference_bundle(pp, "char", "WREN", "identity")
    assert bundle.by_role("identity"), "front/profile still resolve as identity refs"
    assert bundle.hero_subjects() == frozenset(), "but NO usable hero present"


def test_pool_blob_is_never_auto_active(tmp_path):
    pp = ProjectPaths.from_root(tmp_path)
    pool = pp.pool_dir("char", "jade", "identity", "base")
    _write_png(pool / "deadbeef.png")
    bundle = resolve_reference_bundle(pp, "char", "JADE", "identity")
    assert bundle.by_role("identity") == ()


def test_promote_round_trips_to_shelf(tmp_path):
    from recoil.workspace.sidecar import promote_to_canonical
    pp = ProjectPaths.from_root(tmp_path)
    src = pp.pool_dir("char", "old_man", "identity", "base") / "candidate.png"
    _write_png(src)
    promote_to_canonical(src, "char", "old man", tmp_path, kind="identity")
    bundle = resolve_reference_bundle(pp, "char", "old man", "identity")
    ids = bundle.by_role("identity")
    assert ids and ids[0].source == "shelf" and ids[0].is_hero


def test_promote_deletes_stale_underscore_hero_so_new_wins(tmp_path):
    """codex MAJOR-1: a pre-existing underscore shelf hero (jade_identity.png) must
    NOT survive promotion and out-resolve the new hyphen hero. promote_to_canonical
    deletes BOTH stem forms; afterward resolve_reference_bundle + ProjectPaths.resolve_ref
    return the new hyphen shelf hero, and the stale underscore file is gone."""
    from recoil.workspace.sidecar import promote_to_canonical
    pp = ProjectPaths.from_root(tmp_path)
    look = pp.asset_look_dir("char", "jade", "base")
    stale = look / "jade_identity.png"          # legacy underscore shelf hero
    _write_png(stale)
    src = pp.pool_dir("char", "jade", "identity", "base") / "candidate.png"
    _write_png(src)
    promote_to_canonical(src, "char", "jade", tmp_path, kind="identity")
    assert not stale.exists(), "stale underscore shelf hero must be deleted on promote"
    bundle = resolve_reference_bundle(pp, "char", "jade", "identity")
    ids = bundle.by_role("identity")
    assert ids and ids[0].source == "shelf" and ids[0].is_hero
    assert ids[0].path.name == ref_filename("jade", "identity", "png"), \
        "the new hyphen shelf hero wins; the stale underscore file is gone"
