"""Unit tests for model selection feature."""

from __future__ import annotations

from unittest.mock import patch

import pytest


@pytest.fixture()
def tmp_tribunal_home(tmp_path, monkeypatch):
    """Override SKILLFIELD_HOME to a temp dir for config isolation."""
    monkeypatch.setenv("SKILLFIELD_HOME", str(tmp_path))
    # Bust any cached config imports
    import importlib

    import launcher.config as cfg_mod
    importlib.reload(cfg_mod)
    return tmp_path


# ---------------------------------------------------------------------------
# Config helper tests
# ---------------------------------------------------------------------------


def test_set_and_get_model(tmp_tribunal_home):
    from launcher.config import get_model, set_model

    set_model("claude-opus-4-5")
    assert get_model() == "claude-opus-4-5"


def test_clear_model(tmp_tribunal_home):
    from launcher.config import clear_model, get_model, set_model

    set_model("claude-sonnet-4-5")
    clear_model()
    assert get_model() is None


def test_get_model_returns_none_when_unset(tmp_tribunal_home):
    from launcher.config import get_model

    assert get_model() is None


# ---------------------------------------------------------------------------
# Custom model management tests
# ---------------------------------------------------------------------------


def test_add_custom_model(tmp_tribunal_home):
    from launcher.config import add_custom_model, get_custom_models

    add_custom_model("minimax/MiniMax-Text-01", name="MiniMax Text 01", provider="MiniMax")
    custom = get_custom_models()
    assert len(custom) == 1
    assert custom[0]["id"] == "minimax/MiniMax-Text-01"
    assert custom[0]["name"] == "MiniMax Text 01"
    assert custom[0]["provider"] == "MiniMax"


def test_add_custom_model_replaces_existing(tmp_tribunal_home):
    from launcher.config import add_custom_model, get_custom_models

    add_custom_model("minimax/MiniMax-Text-01", name="Old Name")
    add_custom_model("minimax/MiniMax-Text-01", name="New Name", provider="MiniMax")
    custom = get_custom_models()
    assert len(custom) == 1
    assert custom[0]["name"] == "New Name"


def test_remove_custom_model(tmp_tribunal_home):
    from launcher.config import add_custom_model, get_custom_models, remove_custom_model

    add_custom_model("THUDM/glm-4-9b-chat", name="GLM-4")
    assert remove_custom_model("THUDM/glm-4-9b-chat") is True
    assert get_custom_models() == []


def test_remove_custom_model_not_found(tmp_tribunal_home):
    from launcher.config import remove_custom_model

    assert remove_custom_model("does-not-exist") is False


def test_custom_model_passthrough(tmp_tribunal_home):
    """Setting a custom/third-party model ID passes it through without error."""
    from launcher.config import get_model, set_model

    set_model("openai/gpt-4o")
    assert get_model() == "openai/gpt-4o"


# ---------------------------------------------------------------------------
# Launch injection tests
# ---------------------------------------------------------------------------


def _run_launch_capture(extra_args, model=None):
    """Helper: call launch_claude and capture os.execvpe args."""
    captured: list[list[str]] = []

    def fake_execvpe(path, args, env):
        captured.append(list(args))

    with (
        patch("launcher.wrapper.find_claude_binary", return_value="/usr/bin/claude"),
        patch("launcher.wrapper.verify_access", return_value=(True, "")),
        patch("launcher.wrapper.build_env", return_value={}),
        patch("launcher.wrapper._check_plugin_version"),
        patch("launcher.wrapper._start_hook_runner_daemon"),
        patch("os.execvpe", side_effect=fake_execvpe),
        patch("sys.platform", "linux"),
    ):
        import launcher.wrapper as wrapper
        try:
            wrapper.launch_claude(extra_args=extra_args, model=model)
        except Exception:
            pass

    return captured


def test_model_injected_into_launch_args(tmp_tribunal_home):
    """Config model is injected when user has not passed --model."""
    from launcher.config import set_model

    set_model("claude-haiku-3-5")
    captured = _run_launch_capture(extra_args=[])

    assert captured, "execvpe was not called"
    args = captured[0]
    assert "--model" in args
    assert args[args.index("--model") + 1] == "claude-haiku-3-5"


def test_user_model_not_overridden(tmp_tribunal_home):
    """If user passes --model in extra_args, config model is NOT injected."""
    from launcher.config import set_model

    set_model("claude-opus-4-5")
    captured = _run_launch_capture(extra_args=["--model", "claude-sonnet-4-5"])

    assert captured, "execvpe was not called"
    args = captured[0]
    model_indices = [i for i, a in enumerate(args) if a == "--model"]
    assert len(model_indices) == 1, f"Expected exactly one --model, got: {args}"
    assert args[model_indices[0] + 1] == "claude-sonnet-4-5"


def test_third_party_model_injected(tmp_tribunal_home):
    """Third-party model IDs are passed through as-is."""
    from launcher.config import set_model

    set_model("openai/gpt-4o")
    captured = _run_launch_capture(extra_args=[])

    assert captured, "execvpe was not called"
    args = captured[0]
    assert "--model" in args
    assert args[args.index("--model") + 1] == "openai/gpt-4o"


# ---------------------------------------------------------------------------
# CLI command tests
# ---------------------------------------------------------------------------


def test_model_list_command():
    """tribunal model list runs without error."""
    from io import StringIO

    from launcher.cli import main

    with patch("sys.stdout", new_callable=StringIO):
        try:
            main(["--no-banner", "model", "list"])
        except SystemExit as e:
            assert e.code in (None, 0), f"Unexpected exit code: {e.code}"


def test_model_set_command(tmp_tribunal_home):
    """tribunal model set persists the model."""
    from launcher.cli import main
    from launcher.config import get_model

    try:
        main(["--no-banner", "model", "set", "claude-sonnet-4-5"])
    except SystemExit:
        pass
    assert get_model() == "claude-sonnet-4-5"


def test_model_set_unknown_warns_without_force(tmp_tribunal_home, capsys):
    """Setting an unrecognised model prints a warning without --force."""
    from launcher.cli import main

    try:
        main(["--no-banner", "model", "set", "some-unknown-model"])
    except SystemExit:
        pass
    # Rich may go to stdout or stderr; just confirm model is still set
    from launcher.config import get_model
    assert get_model() == "some-unknown-model"


def test_model_set_force_skips_warning(tmp_tribunal_home):
    """--force suppresses the unrecognised-model warning."""
    from launcher.cli import main
    from launcher.config import get_model

    try:
        main(["--no-banner", "model", "set", "some-unknown-model", "--force"])
    except SystemExit:
        pass
    assert get_model() == "some-unknown-model"


def test_model_add_command(tmp_tribunal_home):
    """tribunal model add saves a custom model."""
    from launcher.cli import main
    from launcher.config import get_custom_models

    try:
        main(["--no-banner", "model", "add", "minimax/MiniMax-Text-01",
              "--name", "MiniMax", "--provider", "MiniMax"])
    except SystemExit:
        pass
    custom = get_custom_models()
    assert any(m["id"] == "minimax/MiniMax-Text-01" for m in custom)


def test_model_remove_command(tmp_tribunal_home):
    """tribunal model remove deletes a custom model."""
    from launcher.cli import main
    from launcher.config import add_custom_model, get_custom_models

    add_custom_model("THUDM/glm-4-9b-chat", name="GLM-4")

    try:
        main(["--no-banner", "model", "remove", "THUDM/glm-4-9b-chat"])
    except SystemExit:
        pass
    assert get_custom_models() == []


def test_model_remove_builtin_fails(tmp_tribunal_home):
    """Removing a built-in model exits with error."""
    from launcher.cli import main

    with pytest.raises(SystemExit) as exc_info:
        main(["--no-banner", "model", "remove", "claude-sonnet-4-5"])
    assert exc_info.value.code != 0
