"""Tests for the SWE-bench CLI subcommands (generate, score, smoke)."""

from __future__ import annotations

from pathlib import Path

from evals.swebench import cli as swebench_cli
from evals.swebench.types import (
    ConditionGenerationSummary,
    GenerationRunSummary,
    ScoreRunSummary,
    ScoringSmokeSubsetSummary,
)


def test_generate_lite_cli_parses_and_forwards_jobs(monkeypatch, capsys, tmp_path) -> None:
    captured: dict[str, object] = {}

    def _fake_generate(**kwargs):
        captured.update(kwargs)
        return GenerationRunSummary(
            run_id="demo-run",
            run_dir=tmp_path / "evals" / "swebench_runs" / "demo-run",
            instance_count=2,
            condition_summaries=(
                ConditionGenerationSummary(
                    condition="baseline",
                    predictions_path=tmp_path / "baseline" / "predictions.jsonl",
                    total_instances=2,
                    generated=2,
                    resumed=0,
                    empty_patch_count=0,
                    request_error_count=0,
                ),
            ),
        )

    monkeypatch.setattr(swebench_cli, "generate_lite_predictions", _fake_generate)
    exit_code = swebench_cli.main(
        [
            "generate-lite",
            "--run-id",
            "demo-run",
            "--conditions",
            "baseline,llmdebug",
            "--openai-base-url",
            "http://localhost:19000",
            "--openai-model",
            "local-model",
            "--no-openai-http2",
            "--openai-async",
            "--jobs",
            "4",
        ]
    )

    assert exit_code == 0
    assert captured["run_id"] == "demo-run"
    assert captured["jobs"] == 4
    assert captured["openai_http2"] is False
    assert captured["openai_async"] is True
    assert captured["conditions"] == "baseline,llmdebug"
    assert "Run directory:" in capsys.readouterr().out


def test_prepare_handoff_fails_when_one_condition_missing(monkeypatch, capsys, tmp_path) -> None:
    run_dir = tmp_path / "demo-run"
    (run_dir / "baseline").mkdir(parents=True, exist_ok=True)
    (run_dir / "instance_ids.txt").write_text("inst-1\n", encoding="utf-8")
    (run_dir / "run_metadata.json").write_text('{"run_id":"demo-run"}\n', encoding="utf-8")
    (run_dir / "baseline" / "predictions.jsonl").write_text(
        (
            '{"instance_id":"inst-1",'
            '"model_patch":"diff --git a/a.py b/a.py\\n",'
            '"model_name_or_path":"baseline-model"}\n'
        ),
        encoding="utf-8",
    )

    monkeypatch.setattr(swebench_cli, "run_dir_for_id", lambda _run_id: run_dir)
    exit_code = swebench_cli.main(["prepare-handoff", "--run-id", "demo-run"])

    assert exit_code == 1
    assert "Handoff validation failed" in capsys.readouterr().out


def test_score_official_cli_surfaces_failure(monkeypatch, capsys, tmp_path) -> None:
    run_dir = tmp_path / "demo-run"
    run_dir.mkdir(parents=True, exist_ok=True)

    def _fake_score(**_kwargs):
        raise RuntimeError("simulated scorer failure")

    monkeypatch.setattr(swebench_cli, "run_official_scoring", _fake_score)
    exit_code = swebench_cli.main(["score-official", "--run-dir", str(run_dir)])

    assert exit_code == 1
    assert "Official scoring failed: simulated scorer failure" in capsys.readouterr().out


def test_score_official_cli_success_prints_condition_summary(monkeypatch, capsys, tmp_path) -> None:
    run_dir = tmp_path / "demo-run"
    run_dir.mkdir(parents=True, exist_ok=True)
    condition_log = run_dir / "official_eval" / "baseline" / "run_evaluation.log"
    condition_log.parent.mkdir(parents=True, exist_ok=True)
    condition_log.write_text("", encoding="utf-8")

    def _fake_score(**_kwargs):
        return ScoreRunSummary(
            run_dir=run_dir,
            condition_summaries=(),
        )

    monkeypatch.setattr(swebench_cli, "run_official_scoring", _fake_score)
    exit_code = swebench_cli.main(["score-official", "--run-dir", str(run_dir)])

    assert exit_code == 0
    assert "Official scoring complete for run dir" in capsys.readouterr().out


def test_generate_lite_cli_rejects_single_condition(monkeypatch, capsys) -> None:
    exit_code = swebench_cli.main(
        [
            "generate-lite",
            "--run-id",
            "demo-run",
            "--conditions",
            "baseline",
            "--openai-base-url",
            "http://localhost:19000",
            "--openai-model",
            "local-model",
        ]
    )

    assert exit_code == 1
    assert (
        "Generation failed: conditions must include exactly baseline,llmdebug"
        in capsys.readouterr().out
    )


def test_prepare_scoring_smoke_cli_success(monkeypatch, capsys, tmp_path) -> None:
    source = tmp_path / "src-run"
    source.mkdir(parents=True, exist_ok=True)
    output = tmp_path / "smoke-run"

    def _fake_prepare(**kwargs):
        assert kwargs["source_run_dir"] == source
        assert kwargs["max_instances"] == 2
        return ScoringSmokeSubsetSummary(
            source_run_dir=source,
            output_run_dir=output,
            instance_count=2,
            conditions=("baseline", "llmdebug"),
        )

    monkeypatch.setattr(swebench_cli, "prepare_scoring_smoke_subset", _fake_prepare)
    exit_code = swebench_cli.main(
        [
            "prepare-scoring-smoke",
            "--run-dir",
            str(source),
            "--max-instances",
            "2",
        ]
    )

    assert exit_code == 0
    out = capsys.readouterr().out
    assert "Scoring smoke subset prepared" in out
    assert "Instances selected: 2" in out
