from __future__ import annotations

from evals import run_eval
from evals.patchers.base import PatchResult
from evals.patchers.openai_compat_patcher import OpenAICompatPatcher, _build_diff_from_changes


def test_openai_force_patch_attempt_builds_fallback_diff(tmp_path, monkeypatch) -> None:
    module_path = "evals.patchers.openai_compat_patcher._propose_patch_via_diff"
    monkeypatch.setattr(
        module_path,
        lambda **kwargs: PatchResult(diff=None, meta={"error": "no_diff_found"}),
    )

    (tmp_path / "buggy.py").write_text("def f():\n    return 1\n", encoding="utf-8")
    (tmp_path / "test_buggy.py").write_text("def test_f():\n    assert True\n", encoding="utf-8")

    patcher = OpenAICompatPatcher(
        base_url="http://127.0.0.1:1234",
        model="dummy",
        response_mode="diff",
        force_patch_attempt=True,
    )
    prompt = (
        "Available files (use exact relative paths):\n"
        "test_buggy.py\n"
        "buggy.py\n\n"
        "Pytest output (stdout):\nfailed\n"
    )
    result = patcher.propose_patch(prompt=prompt, context_dir=tmp_path, cwd=tmp_path)

    assert result.diff is not None
    assert "diff --git a/buggy.py b/buggy.py" in result.diff
    assert "llmdebug-force-attempt" in result.diff
    assert result.meta is not None
    assert result.meta["error"] == "no_diff_found"
    assert result.meta["forced_patch_attempt"] is True
    assert result.meta["forced_patch_target"] == "buggy.py"

    applied, _ = run_eval.apply_diff(tmp_path, result.diff)
    assert applied


def test_openai_force_patch_attempt_disabled_preserves_none(tmp_path, monkeypatch) -> None:
    module_path = "evals.patchers.openai_compat_patcher._propose_patch_via_diff"
    monkeypatch.setattr(
        module_path,
        lambda **kwargs: PatchResult(diff=None, meta={"error": "no_diff_found"}),
    )

    (tmp_path / "buggy.py").write_text("def f():\n    return 1\n", encoding="utf-8")

    patcher = OpenAICompatPatcher(
        base_url="http://127.0.0.1:1234",
        model="dummy",
        response_mode="diff",
        force_patch_attempt=False,
    )
    prompt = (
        "Available files (use exact relative paths):\nbuggy.py\n\nPytest output (stdout):\nfailed\n"
    )
    result = patcher.propose_patch(prompt=prompt, context_dir=tmp_path, cwd=tmp_path)

    assert result.diff is None
    assert result.meta is not None
    assert result.meta["error"] == "no_diff_found"
    assert result.meta["response_mode"] == "diff"
    assert result.meta["api_compat_seed_requested"] is None


def test_build_diff_from_changes_is_patch_apply_compatible(tmp_path) -> None:
    target = tmp_path / "buggy.py"
    before = "def f():\n\n    return 1\n"
    after = "def f():\n\n    return 2\n"
    target.write_text(before, encoding="utf-8")

    diff = _build_diff_from_changes([("buggy.py", before, after)])
    assert "diff --git a/buggy.py b/buggy.py" in diff

    applied, message = run_eval.apply_diff(tmp_path, diff)
    assert applied, message
    assert target.read_text(encoding="utf-8") == after
