"""
test_gate_config_loader.py — gate_config_loader 단위 테스트 (5개 시나리오, 14건)

담당: 닌기르수 (QA 테스터), dev5-team, task-2149
"""

import json
import subprocess
import sys

import pytest

# workspace 경로를 sys.path에 추가
_WORKSPACE = "/home/jay/workspace"
if _WORKSPACE not in sys.path:
    sys.path.insert(0, _WORKSPACE)

import utils.gate_config_loader as gate_config_loader  # type: ignore[import-not-found]
from utils.gate_config_loader import (  # type: ignore[import-not-found]
    load_gate_config,
    is_gate_enabled,
    get_gate_mode,
)


# ---------------------------------------------------------------------------
# 시나리오 1: JSON 파싱 — 5개 게이트 정상 반환
# ---------------------------------------------------------------------------

def test_json_parsing_impact_scanner():
    """impact_scanner 게이트가 올바른 설정으로 반환되어야 한다."""
    cfg = load_gate_config("impact_scanner")
    assert cfg["enabled"] is True
    assert cfg["mode"] == "warn"
    assert cfg["timeout_per_symbol"] == 3
    assert cfg["max_symbols"] == 5


def test_json_parsing_ci_preflight():
    """ci_preflight 게이트가 enabled=True, mode="warn"으로 반환되어야 한다."""
    cfg = load_gate_config("ci_preflight")
    assert cfg["enabled"] is True
    assert cfg["mode"] == "warn"


def test_json_parsing_l1_smoketest():
    """l1_smoketest 게이트가 enabled=True, mode="fail"로 반환되어야 한다."""
    cfg = load_gate_config("l1_smoketest")
    assert cfg["enabled"] is True
    assert cfg["mode"] == "fail"


def test_json_parsing_goal_assertions():
    """goal_assertions 게이트가 allowed_commands 9개와 함께 반환되어야 한다."""
    cfg = load_gate_config("goal_assertions")
    assert cfg["enabled"] is True
    assert cfg["mode"] == "fail"
    assert len(cfg["allowed_commands"]) == 9


def test_json_parsing_unresolved_gate():
    """unresolved_gate 게이트가 max_in_scope_unresolved=3으로 반환되어야 한다."""
    cfg = load_gate_config("unresolved_gate")
    assert cfg["enabled"] is True
    assert cfg["mode"] == "warn"
    assert cfg["max_in_scope_unresolved"] == 3


# ---------------------------------------------------------------------------
# 시나리오 2: Python 로더 함수 동작
# ---------------------------------------------------------------------------

def test_is_gate_enabled_impact_scanner():
    """is_gate_enabled("impact_scanner")은 True를 반환해야 한다."""
    assert is_gate_enabled("impact_scanner") is True


def test_is_gate_enabled_nonexistent():
    """is_gate_enabled("nonexistent")은 False를 반환해야 한다."""
    assert is_gate_enabled("nonexistent") is False


def test_get_gate_mode_l1_smoketest():
    """get_gate_mode("l1_smoketest")은 "fail"을 반환해야 한다."""
    assert get_gate_mode("l1_smoketest") == "fail"


def test_get_gate_mode_ci_preflight():
    """get_gate_mode("ci_preflight")은 "warn"을 반환해야 한다."""
    assert get_gate_mode("ci_preflight") == "warn"


# ---------------------------------------------------------------------------
# 시나리오 3: Bash 호출 동작
# ---------------------------------------------------------------------------

def test_bash_subprocess_get_gate_mode_impact_scanner():
    """subprocess로 get_gate_mode('impact_scanner')를 호출하면 stdout이 'warn\\n'이어야 한다."""
    result = subprocess.run(
        [
            "python3",
            "-c",
            (
                "import sys; "
                "sys.path.insert(0, '/home/jay/workspace'); "
                "from utils.gate_config_loader import get_gate_mode; "
                "print(get_gate_mode('impact_scanner'))"
            ),
        ],
        capture_output=True,
        text=True,
    )
    assert result.stdout == "warn\n"


# ---------------------------------------------------------------------------
# 시나리오 4: 존재하지 않는 게이트 기본값
# ---------------------------------------------------------------------------

def test_load_gate_config_nonexistent_returns_default():
    """load_gate_config("nonexistent")은 {"enabled": False, "mode": "warn"}을 반환해야 한다."""
    cfg = load_gate_config("nonexistent")
    assert cfg == {"enabled": False, "mode": "warn"}


def test_get_gate_mode_nonexistent_returns_warn():
    """get_gate_mode("nonexistent")은 "warn"을 반환해야 한다."""
    assert get_gate_mode("nonexistent") == "warn"


# ---------------------------------------------------------------------------
# 시나리오 5: JSON 오류 처리
# ---------------------------------------------------------------------------

def test_load_gate_config_raises_value_error_on_invalid_json(monkeypatch, tmp_path):
    """잘못된 JSON 파일을 사용하면 load_gate_config 호출 시 ValueError가 발생해야 한다."""
    bad_json_file = tmp_path / "bad_gate_config.json"
    bad_json_file.write_text("{ this is not valid json }", encoding="utf-8")

    monkeypatch.setattr(gate_config_loader, "_CONFIG_PATH", str(bad_json_file))

    with pytest.raises(ValueError):
        load_gate_config("impact_scanner")


def test_load_gate_config_raises_value_error_on_invalid_mode(monkeypatch, tmp_path):
    """mode 필드가 'warn'/'fail'이 아닌 경우 ValueError가 발생하고 메시지에 'warn 또는 fail'이 포함되어야 한다."""
    invalid_mode_file = tmp_path / "invalid_mode_config.json"
    invalid_mode_file.write_text(
        json.dumps({"gates": {"test_gate": {"enabled": True, "mode": "invalid"}}}),
        encoding="utf-8",
    )

    monkeypatch.setattr(gate_config_loader, "_CONFIG_PATH", str(invalid_mode_file))

    with pytest.raises(ValueError, match="또는"):
        load_gate_config("test_gate")
