"""Tests for scripts/gemini_feedback_loop.py — auto-fix retry loop."""

from __future__ import annotations

import importlib.util
import sys
from pathlib import Path

import pytest

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


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


def test_count_persistence(loop_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(loop_module, "EVENTS_DIR", tmp_path)
    assert loop_module._read_count("task-1") == 0
    loop_module._write_count("task-1", 1)
    assert loop_module._read_count("task-1") == 1
    loop_module._write_count("task-1", 5)
    assert loop_module._read_count("task-1") == 5


def test_apply_auto_fixes_handles_missing_tools(loop_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(loop_module.shutil, "which", lambda _name: None)
    summary = loop_module.apply_auto_fixes(tmp_path)
    assert summary["ran"] == []
    assert "ruff" in summary["skipped"]
    assert "black" in summary["skipped"]
    assert "isort" in summary["skipped"]


def test_apply_auto_fixes_runs_available(loop_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    calls: list[list[str]] = []

    def fake_which(name: str):
        return f"/usr/bin/{name}" if name in {"ruff", "black"} else None

    def fake_run(cmd, cwd=None, timeout=60):
        calls.append(cmd)
        return 0, "", ""

    monkeypatch.setattr(loop_module.shutil, "which", fake_which)
    monkeypatch.setattr(loop_module, "_run", fake_run)
    summary = loop_module.apply_auto_fixes(tmp_path)
    tool_names = [r["tool"] for r in summary["ran"]]
    assert tool_names == ["ruff", "black"]
    assert "isort" in summary["skipped"]


def test_loop_exhaustion_adds_label_and_comment(loop_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(loop_module, "EVENTS_DIR", tmp_path)
    label_calls: list[tuple] = []
    comment_calls: list[tuple] = []
    monkeypatch.setattr(loop_module, "gh_add_label", lambda repo, pr, label: (label_calls.append((repo, pr, label)) or {"rc": 0, "stdout": "{}", "stderr": ""}))
    monkeypatch.setattr(loop_module, "gh_comment", lambda repo, pr, body: (comment_calls.append((repo, pr, body)) or {"rc": 0, "stdout": "{}", "stderr": ""}))

    loop_module._write_count("task-77", 3)

    import argparse
    args = argparse.Namespace(task_id="task-77", pr_number=42, repo="OWNER/REPO", max_loops=3, dry_run=False)
    rc = loop_module.loop(args)
    assert rc == 2
    assert label_calls == [("OWNER/REPO", 42, loop_module.HUMAN_LABEL)]
    assert comment_calls and "회장" in comment_calls[0][2]
    assert loop_module._read_count("task-77") == 4


def test_loop_under_limit_returns_zero(loop_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(loop_module, "EVENTS_DIR", tmp_path)
    monkeypatch.setattr(loop_module, "WORKSPACE", tmp_path)
    monkeypatch.setattr(loop_module, "apply_auto_fixes", lambda ws: {"ran": [], "skipped": []})
    monkeypatch.setattr(loop_module, "push_changes", lambda ws, msg: {"changed": False})

    import argparse
    args = argparse.Namespace(task_id="task-88", pr_number=0, repo="OWNER/REPO", max_loops=3, dry_run=False)
    rc = loop_module.loop(args)
    assert rc == 0
    assert loop_module._read_count("task-88") == 1


def test_loop_dry_run_does_not_increment(loop_module, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(loop_module, "EVENTS_DIR", tmp_path)
    import argparse
    args = argparse.Namespace(task_id="task-99", pr_number=0, repo="OWNER/REPO", max_loops=3, dry_run=True)
    rc = loop_module.loop(args)
    assert rc == 0
    assert loop_module._read_count("task-99") == 0
