"""Tests for ievo.core.claude_auth — Claude Code CLI detection + auth."""

from __future__ import annotations

import subprocess
from pathlib import Path
from unittest.mock import patch

from ievo.core.claude_auth import (
    check_claude_auth,
    check_claude_cli,
    check_env_token,
    prompt_claude_auth,
)
from ievo.core.global_config import get_config, load_global_config

# ── check_claude_cli ──────────────────────────────────────────


def test_check_claude_cli_found() -> None:
    with patch("ievo.core.claude_auth.shutil.which", return_value="/usr/bin/claude"):
        assert check_claude_cli() is True


def test_check_claude_cli_not_found() -> None:
    with patch("ievo.core.claude_auth.shutil.which", return_value=None):
        assert check_claude_cli() is False


# ── check_claude_auth ─────────────────────────────────────────


def test_check_claude_auth_authenticated() -> None:
    mock_result = subprocess.CompletedProcess(
        args=[], returncode=0, stdout="Logged in as user@example.com\n", stderr=""
    )
    with (
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.subprocess.run", return_value=mock_result),
    ):
        result = check_claude_auth()
        assert result == "Logged in as user@example.com"


def test_check_claude_auth_empty_stdout_uses_stderr() -> None:
    mock_result = subprocess.CompletedProcess(
        args=[], returncode=0, stdout="", stderr="Authenticated"
    )
    with (
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.subprocess.run", return_value=mock_result),
    ):
        result = check_claude_auth()
        assert result == "Authenticated"


def test_check_claude_auth_empty_output() -> None:
    mock_result = subprocess.CompletedProcess(args=[], returncode=0, stdout="", stderr="")
    with (
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.subprocess.run", return_value=mock_result),
    ):
        result = check_claude_auth()
        assert result == "authenticated"


def test_check_claude_auth_not_authenticated() -> None:
    mock_result = subprocess.CompletedProcess(args=[], returncode=1, stdout="", stderr="")
    with (
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.subprocess.run", return_value=mock_result),
    ):
        assert check_claude_auth() is None


def test_check_claude_auth_no_cli() -> None:
    with patch("ievo.core.claude_auth.check_claude_cli", return_value=False):
        assert check_claude_auth() is None


def test_check_claude_auth_file_not_found() -> None:
    with (
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.subprocess.run", side_effect=FileNotFoundError),
    ):
        assert check_claude_auth() is None


def test_check_claude_auth_timeout() -> None:
    with (
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch(
            "ievo.core.claude_auth.subprocess.run",
            side_effect=subprocess.TimeoutExpired(cmd="claude", timeout=10),
        ),
    ):
        assert check_claude_auth() is None


# ── check_env_token ───────────────────────────────────────────


def test_check_env_token_present() -> None:
    with patch.dict("os.environ", {"CLAUDE_CODE_OAUTH_TOKEN": "sk-ant-test"}):
        assert check_env_token() == "sk-ant-test"


def test_check_env_token_missing() -> None:
    with patch.dict("os.environ", {}, clear=True):
        assert check_env_token() is None


# ── prompt_claude_auth ────────────────────────────────────────


def test_prompt_claude_auth_env_token(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with patch("ievo.core.claude_auth.check_env_token", return_value="sk-ant-test"):
        result = prompt_claude_auth(tmp_path)
        assert result == "env"
    assert get_config(tmp_path, "claude_auth") == "env"


def test_prompt_claude_auth_cli_already_authed(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with (
        patch("ievo.core.claude_auth.check_env_token", return_value=None),
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.check_claude_auth", return_value="authed"),
    ):
        result = prompt_claude_auth(tmp_path)
        assert result == "cli"
    assert get_config(tmp_path, "claude_auth") == "cli"


def test_prompt_claude_auth_cli_login_succeeds(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with (
        patch("ievo.core.claude_auth.check_env_token", return_value=None),
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch(
            "ievo.core.claude_auth.check_claude_auth",
            side_effect=[None, "authed"],
        ),
        patch("builtins.input", return_value="y"),
        patch("ievo.core.claude_auth.subprocess.run"),
    ):
        result = prompt_claude_auth(tmp_path)
        assert result == "cli"


def test_prompt_claude_auth_cli_login_fails(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with (
        patch("ievo.core.claude_auth.check_env_token", return_value=None),
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.check_claude_auth", return_value=None),
        patch("builtins.input", return_value="y"),
        patch("ievo.core.claude_auth.subprocess.run"),
    ):
        result = prompt_claude_auth(tmp_path)
        assert result is None


def test_prompt_claude_auth_cli_login_file_error(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with (
        patch("ievo.core.claude_auth.check_env_token", return_value=None),
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.check_claude_auth", return_value=None),
        patch("builtins.input", return_value="y"),
        patch(
            "ievo.core.claude_auth.subprocess.run",
            side_effect=FileNotFoundError,
        ),
    ):
        result = prompt_claude_auth(tmp_path)
        assert result is None


def test_prompt_claude_auth_cli_login_timeout(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with (
        patch("ievo.core.claude_auth.check_env_token", return_value=None),
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.check_claude_auth", return_value=None),
        patch("builtins.input", return_value="y"),
        patch(
            "ievo.core.claude_auth.subprocess.run",
            side_effect=subprocess.TimeoutExpired(cmd="claude", timeout=120),
        ),
    ):
        result = prompt_claude_auth(tmp_path)
        assert result is None


def test_prompt_claude_auth_no_cli(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with (
        patch("ievo.core.claude_auth.check_env_token", return_value=None),
        patch("ievo.core.claude_auth.check_claude_cli", return_value=False),
    ):
        result = prompt_claude_auth(tmp_path)
        assert result is None


def test_prompt_claude_auth_decline_login(tmp_path: Path) -> None:
    load_global_config(tmp_path)
    with (
        patch("ievo.core.claude_auth.check_env_token", return_value=None),
        patch("ievo.core.claude_auth.check_claude_cli", return_value=True),
        patch("ievo.core.claude_auth.check_claude_auth", return_value=None),
        patch("builtins.input", return_value="n"),
    ):
        result = prompt_claude_auth(tmp_path)
        assert result is None
