"""Test format-aware prompt engine.

Verifies (HISTORICAL — pre-CP-3):
1. Grammar injection works for Puzzle Box format
2. Layer muting works (kinetic_action muted for Puzzle Box)
3. Bleed schedule affects grammar output
4. Legacy mode (no format_rules) still works

CP-3 STATUS (2026-04-26): All 4 tests in this file are SKIPPED.
The visual/ implementation of `build_prompt_sections_from_plan` accepted
`format_rules`, `grammar_context`, and `exposure_level` kwargs that the
canonical pipeline/lib version (the SSOT post-CP-3) does not implement.
This is a known feature delta surfaced by Phase 1 audit's
BEHAVIORAL_DRIFT classification — visual/ had richer format-aware
grammar that pipeline/lib's canonical body does not. Flagged for v2
follow-up (re-port the format-rules layer + grammar bleed into
pipeline/lib if/when Puzzle Box format ships again).

After CP-3 Phase 6 stub: this file's import path resolves through the
stub, but the body of `build_prompt_sections_from_plan` no longer
accepts the kwargs these tests pass — hence `pytest.mark.skip` below.
"""

import sys
from pathlib import Path

import pytest

RECOIL_ROOT = Path(__file__).resolve().parent.parent
if str(RECOIL_ROOT) not in sys.path:
    sys.path.insert(0, str(RECOIL_ROOT))

# CP-3 Phase 8 (2026-04-26): post-stub-deletion bootstrap.
# `lib.prompt_engine` is the SSOT at recoil/pipeline/lib/prompt_engine.py;
# resolves only when recoil/pipeline/ is on sys.path.
_PIPELINE_DIR = str(RECOIL_ROOT / "pipeline")
if _PIPELINE_DIR not in sys.path:
    sys.path.insert(0, _PIPELINE_DIR)

from visual.compiler import load_visual_rules  # noqa: E402

_SKIP_REASON = (
    "CP-3 Phase 6: visual/ format_rules/grammar_context/exposure_level "
    "kwargs not in pipeline/lib canonical signature. Feature delta "
    "flagged for v2 follow-up (see recoil/docs/prompt-engine-audit.md "
    "§ Phase 6 migration log)."
)


@pytest.mark.skip(reason=_SKIP_REASON)
def test_grammar_injection():
    """Test that grammar tag produces lens language in prompt."""
    from recoil.pipeline._lib.prompt_engine import build_prompt_sections_from_plan

    rules = load_visual_rules("puzzle_box")

    shot = {
        "prompt_data": {
            "shot_type": "CU",
            "focal_length": "85mm",
            "camera_movement": "static",
            "prompt_skeleton": {
                "subject_line": "Sadie in profile against apartment window",
                "environment_line": "Rain on glass behind her",
            },
            "grammar_tag": "SADIE",
        },
        "routing_data": {"is_env_only": False},
        "asset_data": {"characters": []},
        "spatial_data": {},
    }

    grammars = {
        "SADIE": "85mm telephoto, shallow depth of field, cool cyan",
        "DUSTY": "9.8mm ultra-wide, deep focus, warm amber",
    }

    sections = build_prompt_sections_from_plan(
        shot=shot,
        bible={},
        project_config={},
        episode=1,
        format_rules=rules,
        grammar_context=grammars,
        exposure_level=1,
    )

    grammar_sections = [s for s in sections if s["id"] == "grammar_injection"]
    assert len(grammar_sections) == 1
    assert "85mm telephoto" in grammar_sections[0]["text"]
    assert "ultra-wide" not in grammar_sections[0]["text"]
    print("  [OK] Grammar injection (exposure 1 — pure SADIE)")


@pytest.mark.skip(reason=_SKIP_REASON)
def test_grammar_bleed():
    """Test grammar bleed at exposure 4 (full merge)."""
    from recoil.pipeline._lib.prompt_engine import build_prompt_sections_from_plan

    rules = load_visual_rules("puzzle_box")

    shot = {
        "prompt_data": {
            "shot_type": "CU",
            "focal_length": "50mm",
            "camera_movement": "static",
            "prompt_skeleton": {
                "subject_line": "Merged visual grammar",
                "environment_line": "",
            },
            "grammar_tag": "SADIE",
        },
        "routing_data": {"is_env_only": False},
        "asset_data": {"characters": []},
        "spatial_data": {},
    }

    grammars = {
        "SADIE": "85mm telephoto, shallow depth of field",
        "DUSTY": "9.8mm ultra-wide, deep focus, barrel distortion",
    }

    sections = build_prompt_sections_from_plan(
        shot=shot,
        bible={},
        project_config={},
        episode=16,
        format_rules=rules,
        grammar_context=grammars,
        exposure_level=4,
    )

    grammar_sections = [s for s in sections if s["id"] == "grammar_injection"]
    text = grammar_sections[0]["text"]
    assert "85mm" in text or "telephoto" in text
    assert "ultra-wide" in text or "barrel distortion" in text
    print("  [OK] Grammar bleed (exposure 4 — full merge)")


@pytest.mark.skip(reason=_SKIP_REASON)
def test_layer_muting():
    """Test that kinetic_action is muted for Puzzle Box."""
    from recoil.pipeline._lib.prompt_engine import build_prompt_sections_from_plan

    rules = load_visual_rules("puzzle_box")

    shot = {
        "prompt_data": {
            "shot_type": "MS",
            "focal_length": "50mm",
            "camera_movement": "static",
            "prompt_skeleton": {
                "subject_line": "Atmospheric scene",
                "environment_line": "Neon corridor",
            },
            "kinetic_action": "Running through corridor",
        },
        "routing_data": {"is_env_only": False},
        "asset_data": {"characters": []},
        "spatial_data": {},
    }

    sections = build_prompt_sections_from_plan(
        shot=shot,
        bible={},
        project_config={},
        episode=1,
        format_rules=rules,
    )

    kinetic_sections = [s for s in sections if s["id"] == "kinetic_action"]
    for ks in kinetic_sections:
        assert ks["text"] == "", (
            f"kinetic_action should be muted for Puzzle Box, got: {ks['text']!r}"
        )
    print("  [OK] Layer muting (kinetic_action)")


@pytest.mark.skip(reason=_SKIP_REASON)
def test_legacy_mode():
    """Test that no format_rules = legacy behavior (all layers active)."""
    from recoil.pipeline._lib.prompt_engine import build_prompt_sections_from_plan

    shot = {
        "prompt_data": {
            "shot_type": "MS",
            "focal_length": "50mm",
            "camera_movement": "static",
            "prompt_skeleton": {
                "subject_line": "Action scene",
                "environment_line": "Corridor",
            },
            "kinetic_action": "Running",
        },
        "routing_data": {"is_env_only": False},
        "asset_data": {"characters": []},
        "spatial_data": {},
    }

    sections = build_prompt_sections_from_plan(
        shot=shot,
        bible={},
        project_config={},
        episode=1,
        format_rules=None,
    )

    layer_ids = [s["id"] for s in sections]
    assert "camera_line" in layer_ids
    assert "kinetic_action" in layer_ids
    print("  [OK] Legacy mode (no format_rules)")


# NOTE: The __main__ block was removed in CP-3 debug R1 (2026-04-26).
# It bypassed the @pytest.mark.skip decorators on all 4 tests and would crash
# with TypeError because pipeline/lib's canonical build_prompt_sections_from_plan
# does not accept the format_rules/grammar_context/exposure_level kwargs the
# legacy visual/ implementation accepted. Run via `pytest visual/test_prompt_engine.py`
# instead — pytest honors the skip markers correctly.
