"""Promotion copies pool turn views into role-qualified shelf slots and round-trips
through resolve_character_bundle. Fixture project only -- never touches tartarus."""
from pathlib import Path
import pytest
from PIL import Image
from recoil.core.paths import ProjectPaths
from recoil.pipeline.tools.promote_turn_views import promote_turn_views


def _png(p: Path):
    p.parent.mkdir(parents=True, exist_ok=True)
    Image.new("RGB", (8, 8)).save(p)


def test_promote_copies_and_round_trips(tmp_path, monkeypatch):
    root = tmp_path / "fixture_project"
    paths = ProjectPaths(project_root=root)
    monkeypatch.setattr(ProjectPaths, "for_project", classmethod(lambda cls, project=None: paths))
    look = paths.asset_look_dir("char", "wren")
    _png(look / "wren-identity.png")
    _png(look / "pool" / "turn" / "wren_turn_front-4x_v01.png")
    out = promote_turn_views("fixture_project", "wren",
                             mapping={"front": "pool/turn/wren_turn_front-4x_v01.png"}, apply=True)
    assert out["promoted"] == ["front"]
    assert (look / "turn" / "wren-turn-front.png").is_file()
    # pool source NOT deleted
    assert (look / "pool" / "turn" / "wren_turn_front-4x_v01.png").is_file()


def test_dry_run_writes_nothing(tmp_path, monkeypatch):
    root = tmp_path / "fixture_project"
    paths = ProjectPaths(project_root=root)
    monkeypatch.setattr(ProjectPaths, "for_project", classmethod(lambda cls, project=None: paths))
    look = paths.asset_look_dir("char", "wren")
    _png(look / "pool" / "turn" / "wren_turn_front-4x_v01.png")
    promote_turn_views("fixture_project", "wren",
                       mapping={"front": "pool/turn/wren_turn_front-4x_v01.png"}, apply=False)
    assert not (look / "turn" / "wren-turn-front.png").exists()


def test_promote_rejects_bad_inputs_fail_closed(tmp_path, monkeypatch):
    root = tmp_path / "fixture_project"
    paths = ProjectPaths(project_root=root)
    monkeypatch.setattr(ProjectPaths, "for_project", classmethod(lambda cls, project=None: paths))
    look = paths.asset_look_dir("char", "wren")
    _png(look / "pool" / "turn" / "wren_turn_front-4x_v01.png")
    good = "pool/turn/wren_turn_front-4x_v01.png"
    with pytest.raises(ValueError):  # unknown view
        promote_turn_views("fixture_project", "wren", mapping={"sideways": good}, apply=True)
    with pytest.raises(ValueError):  # .. escape
        promote_turn_views("fixture_project", "wren", mapping={"front": "../escape.png"}, apply=True)
    with pytest.raises(ValueError):  # absolute path
        promote_turn_views("fixture_project", "wren", mapping={"front": "/etc/hosts.png"}, apply=True)
    with pytest.raises(ValueError):  # missing source
        promote_turn_views("fixture_project", "wren", mapping={"front": "pool/turn/nope.png"}, apply=True)
    assert not (look / "turn" / "wren-turn-front.png").exists(), "no partial promotion on a bad map"


def test_promote_threequarter_canonical_token(tmp_path, monkeypatch):
    """The pool 'three-quarter' source promotes to the canonical no-separator
    'threequarter' shelf token via the explicit --view mapping."""
    root = tmp_path / "fixture_project"
    paths = ProjectPaths(project_root=root)
    monkeypatch.setattr(ProjectPaths, "for_project", classmethod(lambda cls, project=None: paths))
    look = paths.asset_look_dir("char", "jade")
    _png(look / "jade-identity.png")
    _png(look / "pool" / "turn" / "jade_turn_three-quarter_v01.png")
    promote_turn_views("fixture_project", "jade",
                       mapping={"threequarter": "pool/turn/jade_turn_three-quarter_v01.png"}, apply=True)
    assert (look / "turn" / "jade-turn-threequarter.png").is_file()
