"""tests/regression/test_review_thread_guard.py — Group 1 (4건).

task-2472 regression: Gemini review thread 임의 resolve 차단 검증.

1. test_resolve_low_severity_no_evidence_ok
2. test_resolve_medium_severity_without_evidence_rejected
3. test_resolve_with_evidence_allowed_and_audited
4. test_resolve_audit_missing_rejects
"""
from __future__ import annotations

import importlib.util
import json
import sys
from pathlib import Path

import pytest

WORKTREE = Path(__file__).resolve().parents[2]


def _load(mod_name: str, rel: str):
    path = WORKTREE / rel
    spec = importlib.util.spec_from_file_location(mod_name, str(path))
    assert spec is not None and spec.loader is not None, f"spec load 실패: {path}"
    mod = importlib.util.module_from_spec(spec)
    sys.modules[mod_name] = mod
    spec.loader.exec_module(mod)
    return mod


rtg = _load("review_thread_guard", "utils/review_thread_guard.py")


# ---------------------------------------------------------------------------
# Test 1: low severity → evidence 없어도 resolve 허용
# ---------------------------------------------------------------------------

def test_resolve_low_severity_no_evidence_ok():
    """low severity는 evidence 없이 resolve 허용."""
    result = rtg.can_resolve_thread(
        "thread-001",
        "low",
        actor="test-bot",
        approval_evidence=None,
    )
    assert result["ok"] is True
    assert "허용" in result["reason"]
    assert result["detail"]["severity"] == "low"
    assert result["detail"]["approval_evidence"] is None


# ---------------------------------------------------------------------------
# Test 2: medium severity, evidence 없이 → reject
# ---------------------------------------------------------------------------

def test_resolve_medium_severity_without_evidence_rejected():
    """medium thread는 chairman approval evidence 없이 resolve 시도 → reject."""
    result = rtg.can_resolve_thread(
        "thread-medium-001",
        "medium",
        actor="odin-bot",
        approval_evidence=None,
    )
    assert result["ok"] is False
    assert "medium" in result["reason"] or "evidence" in result["reason"].lower()
    assert result["detail"]["severity"] == "medium"
    assert result["detail"]["approval_evidence"] is None


# ---------------------------------------------------------------------------
# Test 3: medium/high + 유효한 evidence → 허용 + audit jsonl 추가됨
# ---------------------------------------------------------------------------

def test_resolve_with_evidence_allowed_and_audited(tmp_path):
    """유효한 evidence와 함께 high resolve → ok=True + audit jsonl 기록."""
    evidence = {
        "approved_by": "chairman",
        "evidence_path": "/tmp/evidence.json",
        "ts": "2026-05-07T00:00:00Z",
    }

    # can_resolve 먼저 검증
    gate = rtg.can_resolve_thread(
        "thread-high-001",
        "high",
        actor="test-bot",
        approval_evidence=evidence,
    )
    assert gate["ok"] is True, f"can_resolve failed: {gate['reason']}"

    # audit 기록 (tmp_path를 workspace로 사용)
    audit_path = rtg.record_resolution_audit(
        task_id="task-2472",
        pr_number=99,
        thread_id="thread-high-001",
        severity="high",
        actor="test-bot",
        approval_evidence=evidence,
        result="allowed",
        reason="chairman approved",
        workspace=tmp_path,
    )

    assert audit_path.exists(), "audit jsonl 파일이 생성되지 않았음"
    lines = audit_path.read_text(encoding="utf-8").strip().splitlines()
    assert len(lines) >= 1

    record = json.loads(lines[-1])
    assert record["task_id"] == "task-2472"
    assert record["thread_id"] == "thread-high-001"
    assert record["severity"] == "high"
    assert record["result"] == "allowed"
    assert "evidence_hash" in record
    assert record["actor"] == "test-bot"


# ---------------------------------------------------------------------------
# Test 4: audit 기록 실패 시 reject (os.write 차단으로 검증)
# ---------------------------------------------------------------------------

def test_resolve_audit_missing_rejects(tmp_path, monkeypatch):
    """audit write 차단 시 record_resolution_audit 실패 → exception 발생."""
    evidence = {
        "approved_by": "chairman",
        "evidence_path": "/tmp/ev.json",
        "ts": "2026-05-07T01:00:00Z",
    }

    # os.write를 raise로 교체하여 audit 쓰기 실패 시뮬레이션
    original_os_write = rtg.os.write

    def _blocked_write(*args, **kwargs):
        del args, kwargs
        raise OSError("디렉토리 read-only (mock)")

    monkeypatch.setattr(rtg.os, "write", _blocked_write)

    with pytest.raises((OSError, Exception)):
        rtg.record_resolution_audit(
            task_id="task-2472",
            pr_number=99,
            thread_id="thread-audit-block",
            severity="high",
            actor="test-bot",
            approval_evidence=evidence,
            result="allowed",
            reason="audit blocked test",
            workspace=tmp_path,
        )

    # os.write 복원
    monkeypatch.setattr(rtg.os, "write", original_os_write)
