"""
anu_v2/tests/test_g4_integration_2562.py — task-2562 G4 통합 시나리오

회장 §명시 통합 검증:
- G3 PASS 직후 G4 호출 흐름 (finish-task.sh line 830 부근 hook)
- Lv.3+ hard 분기: action=PR_OPEN_BLOCKED → .g4-failed marker
- fix_loop counter 누적 후 cap
- scope_violation 즉시 ESCALATED (fix_loop 0)
- OAuth-personal 강제 (GEMINI_API_KEY 거부 어셀션)
"""

from __future__ import annotations

import sys
from pathlib import Path
from unittest.mock import patch

import pytest

ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "scripts"))

import gemini_cli_gate_check as g4  # type: ignore[import-not-found]  # noqa: E402


def _make_workspace(tmp_path: Path) -> Path:
    ws = tmp_path / "ws"
    (ws / "memory" / "events").mkdir(parents=True, exist_ok=True)
    (ws / "memory" / "tasks").mkdir(parents=True, exist_ok=True)
    return ws


def _write_task_md(ws: Path, task_id: str, level: str) -> Path:
    p = ws / "memory" / "tasks" / f"{task_id}.md"
    p.write_text(f"# {task_id}\n\n## 레벨\n{level}\n", encoding="utf-8")
    return p


# -------- 1. G3 PASS 직후 G4 호출: Lv.3+ hard FAIL --------


def test_lv3plus_hard_fail_creates_g4_failed_marker(monkeypatch, tmp_path):
    monkeypatch.delenv("GEMINI_API_KEY", raising=False)
    ws = _make_workspace(tmp_path)
    task_file = _write_task_md(ws, "task-2562-int-1", "Lv.3+")

    fake = {
        "risks": [{"severity": "critical", "description": "ctrl-plane risk"}],
        "suggestions": [],
    }
    with patch.object(g4, "_run_gemini_cli", return_value=(fake, None)):
        res = g4.gemini_cli_gate_check(
            task_file=str(task_file),
            affected_files=["x.py"],
            workspace_root=str(ws),
            task_id="task-2562-int-1",
        )
    assert res["level"] == "lv3plus"
    assert res["action"] == "PR_OPEN_BLOCKED"
    assert (ws / "memory" / "events" / "task-2562-int-1.g4-failed").exists()


# -------- 2. fix_loop accumulates and caps --------


def test_fix_loop_counter_increments_then_caps(monkeypatch, tmp_path):
    monkeypatch.delenv("GEMINI_API_KEY", raising=False)
    ws = _make_workspace(tmp_path)
    task_file = _write_task_md(ws, "task-2562-int-2", "Lv.3+")

    fake = {
        "risks": [{"severity": "critical", "description": "x"}],
        "suggestions": [],
    }
    with patch.object(g4, "_run_gemini_cli", return_value=(fake, None)):
        r1 = g4.gemini_cli_gate_check(
            task_file=str(task_file),
            affected_files=[],
            workspace_root=str(ws),
            task_id="task-2562-int-2",
        )
        r2 = g4.gemini_cli_gate_check(
            task_file=str(task_file),
            affected_files=[],
            workspace_root=str(ws),
            task_id="task-2562-int-2",
        )
        r3 = g4.gemini_cli_gate_check(
            task_file=str(task_file),
            affected_files=[],
            workspace_root=str(ws),
            task_id="task-2562-int-2",
        )
    assert r1["fix_loop_count"] == 1
    assert r2["fix_loop_count"] == 2
    # r3 → cap에 걸려서 ESCALATED
    assert r3["action"] == "ESCALATED_OWNER_DECISION"
    assert r3["gate_trigger"] == "fix_loop_cap"
    assert (ws / "memory" / "events" / "task-2562-int-2.g4-fix-loop-cap.json").exists()


# -------- 3. scope_violation 즉시 ESCALATED (fix_loop 진입 0) --------


def test_scope_violation_no_fix_loop_progression(monkeypatch, tmp_path):
    monkeypatch.delenv("GEMINI_API_KEY", raising=False)
    ws = _make_workspace(tmp_path)
    task_file = _write_task_md(ws, "task-2562-int-3", "Lv.3+")

    res = g4.gemini_cli_gate_check(
        task_file=str(task_file),
        affected_files=["a.py", "out_of_scope.py"],
        workspace_root=str(ws),
        task_id="task-2562-int-3",
        expected_files=["a.py"],
    )
    assert res["scope_violation"] is True
    assert "out_of_scope.py" in res["scope_violation_extras"]
    assert res["action"] == "ESCALATED_OWNER_DECISION"
    # fix_loop_count 0 (진입 0 어셀션)
    assert res["fix_loop_count"] == 0
    counter = ws / "memory" / "events" / "task-2562-int-3.g4-fix-loop-count"
    # counter 파일 자체가 없어야 fix_loop 진입 0 (또는 0)
    if counter.exists():
        assert counter.read_text().strip() == "0"


# -------- 4. OAuth-personal 강제 (GEMINI_API_KEY 거부) --------


def test_oauth_personal_enforced_in_integration(monkeypatch, tmp_path):
    monkeypatch.setenv("GEMINI_API_KEY", "leak-from-ci")
    ws = _make_workspace(tmp_path)
    task_file = _write_task_md(ws, "task-2562-int-4", "Lv.3+")

    with pytest.raises(RuntimeError) as exc:
        g4.gemini_cli_gate_check(
            task_file=str(task_file),
            affected_files=[],
            workspace_root=str(ws),
            task_id="task-2562-int-4",
        )
    assert "FORBIDDEN_CAPABILITY_USE" in str(exc.value)


# -------- 5. finish-task.sh integration site 정합성 어셀션 --------


def test_finish_task_sh_g4_hook_present():
    """
    finish-task.sh line 830 부근에 [G4-GATE] hook이 존재하는지 정적 검증.
    회장 §명시: G3 PASS 직후, Lv.4 보안 감사 이전.
    """
    script_path = ROOT / "scripts" / "finish-task.sh"
    if not script_path.exists():
        pytest.skip("finish-task.sh not in this repo snapshot")
    content = script_path.read_text(encoding="utf-8")
    assert "[G4-GATE]" in content, "G4-GATE hook missing"
    # G3 PASS 후 G4가 호출되는지 순서 어셀션
    idx_g3 = content.find("[G3-GATE] PASS")
    idx_g4 = content.find("[G4-GATE]")
    idx_lv4 = content.find("Lv.4 보안 감사 검증")
    assert idx_g3 != -1 and idx_g4 != -1 and idx_lv4 != -1
    assert idx_g3 < idx_g4 < idx_lv4, "G3 PASS → G4 → Lv.4 순서 위배"
