from __future__ import annotations

import argparse
from types import SimpleNamespace

import pytest

from evals import run_eval


def test_execution_config_defaults_to_testcontainers() -> None:
    parser = argparse.ArgumentParser()
    run_eval.add_execution_arguments(parser)
    args = parser.parse_args([])
    config = run_eval.build_execution_config_from_args(args)
    assert config.executor == "testcontainers"
    assert config.container_image


def test_execution_config_rejects_invalid_container_env() -> None:
    parser = argparse.ArgumentParser()
    run_eval.add_execution_arguments(parser)
    args = parser.parse_args(["--container-env", "INVALID"])
    with pytest.raises(ValueError, match="expected KEY=VALUE"):
        run_eval.build_execution_config_from_args(args)


def test_run_pytest_dispatches_local_executor(tmp_path, monkeypatch) -> None:
    marker = run_eval.RunResult(returncode=0, duration_sec=0.0, stdout="ok", stderr="")
    monkeypatch.setattr(run_eval, "_run_pytest_local", lambda **kwargs: marker)
    result = run_eval.run_pytest(
        cwd=tmp_path,
        python_args=["-m", "pytest", "-q"],
        condition=run_eval.Condition.TRACEBACK_ONLY,
        timeout_sec=1,
        output_format="json_compact",
        execution=run_eval.ExecutionConfig(executor="local"),
    )
    assert result is marker


def test_run_pytest_dispatches_testcontainers_executor(tmp_path, monkeypatch) -> None:
    marker = run_eval.RunResult(returncode=1, duration_sec=0.0, stdout="", stderr="x")
    monkeypatch.setattr(run_eval, "_run_pytest_testcontainers", lambda **kwargs: marker)
    result = run_eval.run_pytest(
        cwd=tmp_path,
        python_args=["-m", "pytest", "-q"],
        condition=run_eval.Condition.TRACEBACK_ONLY,
        timeout_sec=1,
        output_format="json_compact",
        execution=run_eval.ExecutionConfig(executor="testcontainers"),
    )
    assert result is marker


def test_run_eval_preflights_testcontainers_runtime(tmp_path, monkeypatch, capsys) -> None:
    repo_root = tmp_path / "repo"
    repo_root.mkdir(parents=True, exist_ok=True)
    case_dir = repo_root / "synthetic_cases" / "preflight_case"
    case_dir.mkdir(parents=True, exist_ok=True)

    case = run_eval.CaseSpec(
        case_id="preflight_case",
        path=case_dir,
        category="traceback_controls",
        difficulty="easy",
        snapshot_dependency="none",
        expected_exception="AssertionError",
        tags=["preflight"],
        python_args=["-m", "pytest", "-q"],
        timeout_sec=30,
    )

    monkeypatch.setattr(run_eval, "_REPO_ROOT", repo_root)
    monkeypatch.setattr(run_eval, "load_cases", lambda _cases_dir: [case])
    monkeypatch.setattr(
        run_eval,
        "check_testcontainers_runtime_available",
        lambda: (False, "docker daemon is not reachable"),
    )

    exit_code = run_eval.main(
        [
            "--run-id",
            "preflight-run",
            "--patcher",
            "null",
            "--conditions",
            "traceback_only",
            "--k",
            "1",
        ]
    )
    assert exit_code == 2
    assert "Environment check failed: docker daemon is not reachable" in capsys.readouterr().out


def test_run_eval_prunes_stale_containers_before_testcontainers_run(tmp_path, monkeypatch) -> None:
    repo_root = tmp_path / "repo"
    repo_root.mkdir(parents=True, exist_ok=True)
    case_dir = repo_root / "synthetic_cases" / "cleanup_case"
    case_dir.mkdir(parents=True, exist_ok=True)

    case = run_eval.CaseSpec(
        case_id="cleanup_case",
        path=case_dir,
        category="traceback_controls",
        difficulty="easy",
        snapshot_dependency="none",
        expected_exception="AssertionError",
        tags=[],
        python_args=["-m", "pytest", "-q"],
        timeout_sec=30,
    )

    monkeypatch.setattr(run_eval, "_REPO_ROOT", repo_root)
    monkeypatch.setattr(run_eval, "load_cases", lambda _cases_dir: [case])
    monkeypatch.setattr(
        run_eval,
        "check_testcontainers_runtime_available",
        lambda: (True, "ok"),
    )
    cleanup_calls: dict[str, int] = {}

    def _cleanup(*, grace_sec: int, now_utc=None):
        cleanup_calls["grace_sec"] = grace_sec
        return 0, 0, None

    monkeypatch.setattr(run_eval, "cleanup_stale_eval_containers", _cleanup)
    monkeypatch.setattr(run_eval, "make_patcher", lambda _args: SimpleNamespace(name="stub"))

    def _run(*, case, condition, run_id, run_metadata, **_kwargs):
        return [
            {
                "run_id": run_id,
                "case_id": case.case_id,
                "condition": condition.value,
                "attempt": 1,
                "success": False,
                "run_metadata": dict(run_metadata),
            }
        ]

    monkeypatch.setattr(run_eval, "run_one_condition", _run)

    exit_code = run_eval.main(
        [
            "--run-id",
            "cleanup-run",
            "--patcher",
            "null",
            "--conditions",
            "traceback_only",
            "--k",
            "1",
            "--executor",
            "testcontainers",
        ]
    )

    assert exit_code == 0
    assert cleanup_calls == {"grace_sec": run_eval.DEFAULT_CONTAINER_CLEANUP_STALE_GRACE_SEC}
