"""Unit tests for Full-Stack Blast Radius Impact Analyzer."""
from __future__ import annotations

import json
import os
import subprocess
import sys
import pytest

PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
SCRIPT_PATH = os.path.join(PROJECT_ROOT, "tools", "analysis", "blast_radius.py")


def run_blast_radius(target: str, *extra_args: str) -> dict:
    """Helper to run blast_radius.py and parse JSON output."""
    cmd = [sys.executable, SCRIPT_PATH, "--target", target, "--format", "json", *extra_args]
    result = subprocess.run(cmd, capture_output=True, text=True, cwd=PROJECT_ROOT, encoding="utf-8")
    assert result.returncode == 0, f"Script failed with stderr: {result.stderr}"
    return json.loads(result.stdout)


def test_blast_radius_test_file_is_low_risk() -> None:
    """Test files or isolated leaf files should be LOW risk and unblocked."""
    res = run_blast_radius("tests/unit/test_movement.py")
    assert res["risk_level"] == "LOW"
    assert res["blocked"] is False
    assert res["target"] == "tests/unit/test_movement.py"


def test_blast_radius_core_engine_file() -> None:
    """Core engine files with many dependents should have HIGH/CRITICAL risk."""
    res = run_blast_radius("server/world/game_design_matrix_types.py")
    assert res["risk_level"] in ("HIGH", "CRITICAL")
    assert len(res["affected_files"]) > 0
    any_service = any("game_design_matrix_service" in f for f in res["affected_files"])
    assert any_service, f"Expected game_design_matrix_service in {res['affected_files']}"


def test_blast_radius_acknowledgment_flow() -> None:
    """Acknowledging a target should unblock it."""
    target = "server/world/combat_engine.py"
    res_ack = run_blast_radius(target, "--ack")
    assert res_ack["acknowledged"] is True
    assert res_ack["blocked"] is False


def test_blast_radius_js_client_dependencies() -> None:
    """Modifying a JS module should detect dependent JS files."""
    target = "client/webapp/js/ui/tooltips.js"
    res = run_blast_radius(target)
    assert len(res["affected_files"]) > 0
    # main.js imports tooltips.js
    any_main = any("main.js" in f for f in res["affected_files"])
    assert any_main, f"Expected main.js to import tooltips.js, got: {res['affected_files']}"


def test_blast_radius_dual_stack_catalog() -> None:
    """Modifying server meridian_catalog.py should flag client meridian_catalog.js."""
    target = "server/world/meridian_catalog.py"
    res = run_blast_radius(target)
    any_client_cat = any("meridian_catalog.js" in f for f in res["affected_files"])
    assert any_client_cat, f"Expected client meridian_catalog.js counterpart in {res['affected_files']}"


def test_blast_radius_proto_schema() -> None:
    """Modifying proto/meridian.proto should flag dependent server and client files."""
    target = "proto/meridian.proto"
    res = run_blast_radius(target)
    assert res["risk_level"] in ("HIGH", "CRITICAL")
    any_service = any("meridian" in f for f in res["affected_files"])
    assert any_service, f"Expected meridian services in {res['affected_files']}"


def test_blast_radius_cpp_engine() -> None:
    """Modifying server_cpp FFI should flag python native engine bridge."""
    target = "server_cpp/src/sim_core_ffi.cpp"
    res = run_blast_radius(target)
    any_bridge = any("native_engine_bridge.py" in f for f in res["affected_files"])
    assert any_bridge, f"Expected native_engine_bridge.py in {res['affected_files']}"


def test_blast_radius_matrix_triples() -> None:
    """Querying an Act or Boss entity should retrieve cross_relationships from SQLite."""
    target = "ACT_I_HUNGER"
    res = run_blast_radius(target)
    assert len(res["domain_impacts"]) > 0
    any_rel = any("ACT_CONTAINS_ZONE" in imp or "zone_" in imp for imp in res["domain_impacts"])
    assert any_rel, f"Expected relational triples in {res['domain_impacts']}"
