"""Area #7a residue gate — Visual World Rules SOT + scene_director A047 absorption.

4 strict residue gate (spec §7):
- Gate 1 (structural, JSON parse): VWR v7 rules_schema.json rule_type.enum exact 10-token set.
- Gate 2 (structural, JSON parse): VWR v7 rules_schema.json rule_type.description 안 6-token "등" pattern 0.
- Gate 3 (markdown parse): VWR v7 system.md 안 10-token canonical list 1+ + 6-token "등" residue 0.
- Gate 4 (regex, scene_director v9): A047 3 site signatures 0.

Archive excluded:
- VWR: 1.* ~ 6.202605021400/ excluded.
- scene_director: 6.* ~ 8.202604081200/ excluded.
"""

from __future__ import annotations

import json
import re
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parents[3]  # backend/tests/integration/<this> → repo root (Codex iter 1 F2 흡수: parents[2] 는 backend/ 까지만 도달)
VWR_DIR = REPO_ROOT / "prompts" / "_base" / "visual_world_rules"
SCENE_DIRECTOR_DIR = REPO_ROOT / "prompts" / "_base" / "scene_director"

CANONICAL_RULE_TYPE_ENUM = [
    "possession",
    "transformation",
    "ghost",
    "projection",
    "superpower",
    "body_deformation",
    "time_period",
    "costume",
    "technology",
    "other",
]


def _latest_active_dir(base: Path, version_prefix: str) -> Path:
    """Return the lexicographically latest dir 안 version prefix matching one."""
    candidates = sorted(
        p for p in base.iterdir() if p.is_dir() and p.name.startswith(version_prefix)
    )
    assert candidates, f"no {version_prefix}* dir under {base}"
    return candidates[-1]


@pytest.fixture(scope="module")
def vwr_v7_dir() -> Path:
    return _latest_active_dir(VWR_DIR, "7.")


@pytest.fixture(scope="module")
def scene_director_v9_dir() -> Path:
    return _latest_active_dir(SCENE_DIRECTOR_DIR, "9.")


# --- Gate 1: VWR v7 rules_schema.json rule_type.enum exact 10-token ---


def test_gate_1_vwr_rule_type_enum_exact_ten(vwr_v7_dir: Path) -> None:
    schema_path = vwr_v7_dir / "rules_schema.json"
    schema = json.loads(schema_path.read_text(encoding="utf-8"))
    rule_type_def = schema["properties"]["rules"]["items"]["properties"]["rule_type"]
    assert rule_type_def["type"] == "string", rule_type_def
    assert rule_type_def["enum"] == CANONICAL_RULE_TYPE_ENUM, rule_type_def["enum"]


# --- Gate 2: VWR v7 rules_schema.json description 안 6-token "등" pattern 0 ---


def test_gate_2_vwr_rule_type_description_no_six_token_residue(vwr_v7_dir: Path) -> None:
    schema_path = vwr_v7_dir / "rules_schema.json"
    schema = json.loads(schema_path.read_text(encoding="utf-8"))
    rule_type_desc = schema["properties"]["rules"]["items"]["properties"]["rule_type"]["description"]
    # 6-token + "등" pattern (4 enum 누락): possession, transformation, ghost, time_period, costume, technology 등
    forbidden_six_token = re.compile(
        r"possession,\s*transformation,\s*ghost,\s*time_period,\s*costume,\s*technology\s*등"
    )
    assert not forbidden_six_token.search(rule_type_desc), rule_type_desc
    # description 안 canonical 10-token 정합 (10 enum 모두 substring)
    for token in CANONICAL_RULE_TYPE_ENUM:
        assert token in rule_type_desc, f"missing {token} in description: {rule_type_desc}"


# --- Gate 3: VWR v7 system.md 안 10-token canonical list 1+ + 6-token "등" 0 ---


def test_gate_3_vwr_system_md_canonical_list_and_no_residue(vwr_v7_dir: Path) -> None:
    system_md_path = vwr_v7_dir / "system.md"
    body = system_md_path.read_text(encoding="utf-8")
    # canonical 10-token enumeration 1+ (line 51 또는 정합 위치)
    canonical_list_pattern = re.compile(
        r"possession.*transformation.*ghost.*projection.*superpower.*body_deformation.*time_period.*costume.*technology.*other",
        re.DOTALL,
    )
    assert canonical_list_pattern.search(body), "missing canonical 10-token list in system.md"
    # 6-token + "등" pattern 0 (description drift residue)
    forbidden_six_token = re.compile(
        r"possession,\s*transformation,\s*ghost,\s*time_period,\s*costume,\s*technology\s*등"
    )
    assert not forbidden_six_token.search(body), "6-token + 등 residue in system.md"


# --- Gate 4: scene_director v9 A047 3 site signatures 0 ---


def test_gate_4_scene_director_a047_site1_exclusion_list(
    scene_director_v9_dir: Path,
) -> None:
    """Site 1 (line 5-10) 4-item exclusion list 본체 signature 0."""
    body = (scene_director_v9_dir / "system.md").read_text(encoding="utf-8")
    forbidden_patterns = [
        r"교차편집/몽타주에서 다른 장소의 인물이 번갈아",
        r"영상통화,\s*CCTV,\s*방송 화면,\s*홀로그램,\s*VR,\s*원격 조종/빙의",
        r"V\.O\.\(보이스오버\),\s*내레이션",
        r"변장,\s*쌍둥이 교체,\s*바디더블",
    ]
    for pat in forbidden_patterns:
        assert not re.search(pat, body), f"A047 Site 1 signature hit: {pat}"


def test_gate_4_scene_director_a047_site2_possession_remote_repeat(
    scene_director_v9_dir: Path,
) -> None:
    """Site 2 (line 23-25) 빙의/원격접속 사례 enumeration 0."""
    body = (scene_director_v9_dir / "system.md").read_text(encoding="utf-8")
    forbidden = r"빙의/원격접속 중이면 실제 몸이 안 보이므로 제외"
    assert not re.search(forbidden, body), "A047 Site 2 signature hit"


def test_gate_4_scene_director_a047_site3_parenthetical(
    scene_director_v9_dir: Path,
) -> None:
    """Site 3 (line 32-34) 출력 본문 안 parenthetical (빙의/원격/V.O. 등) 0."""
    body = (scene_director_v9_dir / "system.md").read_text(encoding="utf-8")
    forbidden = r"\(빙의/원격/V\.O\.\s*등\)"
    assert not re.search(forbidden, body), "A047 Site 3 parenthetical hit"


# --- Sanity: VWR SOT reference token in scene_director v9 ---


def test_scene_director_v9_references_vwr_sot(scene_director_v9_dir: Path) -> None:
    body = (scene_director_v9_dir / "system.md").read_text(encoding="utf-8")
    has_vwr_ref = re.search(r"visual_world_rules|VWR|rule_type", body)
    assert has_vwr_ref, "scene_director v9 must reference VWR SOT"
