"""Tests for scripts/gemini_review_gate.py — Gemini review gate."""

from __future__ import annotations

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

import pytest

ROOT = Path(__file__).resolve().parents[2]
SCRIPT = ROOT / "scripts" / "gemini_review_gate.py"


@pytest.fixture(scope="module")
def gate_module():
    spec = importlib.util.spec_from_file_location("gemini_review_gate", SCRIPT)
    assert spec and spec.loader
    mod = importlib.util.module_from_spec(spec)
    sys.modules["gemini_review_gate"] = mod
    spec.loader.exec_module(mod)
    return mod


def test_detect_blocking_en(gate_module) -> None:
    assert gate_module.detect_blocking("There is a critical issue and you must fix it.") == ["critical issue", "must fix"]


def test_detect_blocking_ko(gate_module) -> None:
    matches = gate_module.detect_blocking("이 변경은 차단되어야 합니다 — 필수 수정 항목 있음.")
    assert "차단" in matches and "필수 수정" in matches


def test_detect_blocking_clean(gate_module) -> None:
    assert gate_module.detect_blocking("LGTM — no blocking issues.") == []


def test_call_gemini_mock_success(gate_module, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setenv("GEMINI_REVIEW_MOCK", json.dumps({"text": "must fix the SQL injection", "tokens_in": 100, "tokens_out": 20, "latency_ms": 42}))
    result = gate_module.call_gemini("diff content")
    assert result["ok"] and result["tokens_in"] == 100
    matches = gate_module.detect_blocking(result["text"])
    assert "must fix" in matches


def test_call_gemini_no_key(gate_module, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.delenv("GEMINI_API_KEY", raising=False)
    monkeypatch.delenv("GEMINI_REVIEW_MOCK", raising=False)
    result = gate_module.call_gemini("diff")
    assert not result["ok"]
    assert "GEMINI_API_KEY" in result["error"]


def test_should_call_gemini_dedup(gate_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(gate_module, "CACHE_DIR", tmp_path)
    sha = "deadbeef"
    proceed, reason = gate_module.should_call_gemini(7, sha)
    assert proceed and reason == "ok"
    import hashlib
    cache = tmp_path / f"gemini-{hashlib.sha1(sha.encode()).hexdigest()}.json"
    cache.write_text("{}")
    proceed, reason = gate_module.should_call_gemini(7, sha)
    assert not proceed
    assert "duplicate SHA" in reason


def test_should_call_gemini_debounce(gate_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(gate_module, "CACHE_DIR", tmp_path)
    import time as _t
    debounce_path = tmp_path / "gemini-pr-9.lasttime"
    debounce_path.write_text(str(_t.time()))
    proceed, reason = gate_module.should_call_gemini(9, "newsha")
    assert not proceed and "debounce" in reason


def test_publish_check_run_invokes_gh_api(gate_module, monkeypatch: pytest.MonkeyPatch) -> None:
    captured: dict = {}

    def fake_gh_api_json(args, input_data=None):
        captured["args"] = args
        captured["body"] = json.loads(input_data) if input_data else None
        return 0, '{"id":1}', ""

    monkeypatch.setattr(gate_module, "gh_api_json", fake_gh_api_json)
    res = gate_module.publish_check_run("OWNER/REPO", "abc123", status="completed", conclusion="failure", summary="blocking found")
    assert res["rc"] == 0
    assert "repos/OWNER/REPO/check-runs" in captured["args"]
    assert captured["body"]["name"] == gate_module.CHECK_NAME
    assert captured["body"]["conclusion"] == "failure"
    assert captured["body"]["head_sha"] == "abc123"


def test_gate_blocking_path(gate_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(gate_module, "CACHE_DIR", tmp_path / "cache")
    monkeypatch.setattr(gate_module, "LOG_PATH", tmp_path / "log.jsonl")
    monkeypatch.setenv("GEMINI_REVIEW_MOCK", json.dumps({"text": "blocking — must fix"}))
    monkeypatch.setattr(gate_module, "fetch_pr_diff", lambda _repo, _pr: "")
    monkeypatch.setattr(gate_module, "publish_check_run", lambda *_a, **_kw: {"rc": 0, "stdout": "", "stderr": ""})

    import argparse
    args = argparse.Namespace(
        pr_number=12, commit_sha="abcd1234", repo="OWNER/REPO",
        status="", diff_file="", mode="call", summary="", publish_check=True, force=True,
    )
    rc = gate_module.gate(args)
    assert rc == 1
    log_lines = (tmp_path / "log.jsonl").read_text().strip().splitlines()
    assert log_lines
    rec = json.loads(log_lines[-1])
    assert rec["status"] == "failure"
    assert "must fix" in rec["matches"]


def test_gate_clean_path(gate_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(gate_module, "CACHE_DIR", tmp_path / "cache")
    monkeypatch.setattr(gate_module, "LOG_PATH", tmp_path / "log.jsonl")
    monkeypatch.setenv("GEMINI_REVIEW_MOCK", json.dumps({"text": "looks good — no blocking issues"}))
    monkeypatch.setattr(gate_module, "fetch_pr_diff", lambda _repo, _pr: "")
    monkeypatch.setattr(gate_module, "publish_check_run", lambda *_a, **_kw: {"rc": 0, "stdout": "", "stderr": ""})

    import argparse
    args = argparse.Namespace(
        pr_number=13, commit_sha="zzzz9999", repo="OWNER/REPO",
        status="", diff_file="", mode="call", summary="", publish_check=True, force=True,
    )
    rc = gate_module.gate(args)
    assert rc == 0
    rec = json.loads((tmp_path / "log.jsonl").read_text().strip().splitlines()[-1])
    assert rec["status"] == "success"
    assert rec["matches"] == []
