"""Test parser and compiler on real AFTERIMAGE episodes.

Verifies:
1. Parser correctly extracts shots from actual episode files
2. Grammar extractor finds Sadie and Dusty grammars
3. Compiler produces manifests from real episodes
4. Exposure level calculation is correct
"""

import sys
from pathlib import Path

RECOIL_ROOT = Path(__file__).resolve().parent.parent

if str(RECOIL_ROOT) not in sys.path:
    sys.path.insert(0, str(RECOIL_ROOT))

from recoil.core.paths import projects_root  # noqa: E402
from visual.compiler import load_format_parser, compile_episode_manifest  # noqa: E402
from visual.grammar_extractor import extract_grammars, get_exposure_level  # noqa: E402


def test_grammar_extraction():
    """Extract grammars from AFTERIMAGE characters.md."""
    chars_path = projects_root() / "afterimage" / "bible" / "characters.md"
    if not chars_path.exists():
        print("  [SKIP] AFTERIMAGE characters.md not found")
        return

    grammars = extract_grammars(chars_path)
    assert "SADIE" in grammars, f"SADIE not found in grammars: {list(grammars.keys())}"
    assert "DUSTY" in grammars, f"DUSTY not found in grammars: {list(grammars.keys())}"
    assert "telephoto" in grammars["SADIE"].lower() or "85mm" in grammars["SADIE"]
    assert "wide" in grammars["DUSTY"].lower() or "9.8mm" in grammars["DUSTY"]
    print(f"  [OK] Grammar extraction — SADIE: {grammars['SADIE'][:60]}...")
    print(f"  [OK] Grammar extraction — DUSTY: {grammars['DUSTY'][:60]}...")


def test_exposure_levels():
    """Test exposure level calculation."""
    assert get_exposure_level(1) == 1
    assert get_exposure_level(4) == 1
    assert get_exposure_level(5) == 2
    assert get_exposure_level(8) == 2
    assert get_exposure_level(9) == 3
    assert get_exposure_level(13) == 4
    assert get_exposure_level(16) == 4
    print("  [OK] Exposure levels")


def test_parse_real_episode():
    """Parse real AFTERIMAGE EP01."""
    ep_path = projects_root() / "afterimage" / "episodes" / "ep_01.md"
    if not ep_path.exists():
        print("  [SKIP] ep_01.md not found")
        return

    parser = load_format_parser("puzzle_box")
    text = ep_path.read_text(encoding="utf-8")
    result = parser.parse_episode(text)

    assert result["episode_number"] == 1
    assert result["shot_count"] >= 4, f"Expected >= 4 shots, got {result['shot_count']}"

    # Check that beats are present
    beats = {s["beat"] for s in result["shots"]}
    assert "ENTRY_IMAGE" in beats, f"ENTRY_IMAGE not found in beats: {beats}"
    assert "VOICE" in beats, f"VOICE not found in beats: {beats}"
    assert "LINGER" in beats, f"LINGER not found in beats: {beats}"

    print(f"  [OK] Real episode parse — {result['shot_count']} shots, beats: {beats}")


def test_compile_real_episode():
    """Compile real AFTERIMAGE EP01 into manifests."""
    ep_path = projects_root() / "afterimage" / "episodes" / "ep_01.md"
    chars_path = projects_root() / "afterimage" / "bible" / "characters.md"

    if not ep_path.exists():
        print("  [SKIP] ep_01.md not found")
        return

    text = ep_path.read_text(encoding="utf-8")
    grammars = extract_grammars(chars_path) if chars_path.exists() else {}

    manifests = compile_episode_manifest(
        episode_text=text,
        format_name="puzzle_box",
        project_name="afterimage",
        episode_number=1,
        grammars=grammars,
        exposure_level=1,
    )

    assert len(manifests) >= 4, f"Expected >= 4 manifests, got {len(manifests)}"

    # Verify structure
    for m in manifests:
        assert "job_id" in m
        assert "execution" in m
        assert "payload" in m
        assert "validation" in m
        assert m["execution"]["aspect_ratio"] == "9:16"

    print(f"  [OK] Real episode compile — {len(manifests)} manifests")


if __name__ == "__main__":
    print("Real Episode Tests")
    print("=" * 40)
    test_grammar_extraction()
    test_exposure_levels()
    test_parse_real_episode()
    test_compile_real_episode()
    print("=" * 40)
    print("ALL TESTS PASSED")
