from __future__ import annotations

import importlib
from contextlib import contextmanager

from typer.testing import CliRunner

from cli.exceptions import CLIError
from cli.keychain import store_api_key


def _reload_cli_module():
    import cli.main as cli_main

    return importlib.reload(cli_main)


def _valid_key(letter: str) -> str:
    return "ctxme_" + (letter * 32)


def test_auth_status_shows_environment_source(monkeypatch):
    monkeypatch.setenv("CLI__API_KEY", _valid_key("A"))
    cli_main = _reload_cli_module()

    def _boom(*_args, **_kwargs):
        raise CLIError("backend unavailable")

    monkeypatch.setattr("cli.commands.auth._http_client", _boom)

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["auth", "status"])

    assert result.exit_code == 0
    assert "from environment" in result.stdout


def test_auth_status_shows_keychain_source(monkeypatch, in_memory_keyring):
    cli_main = _reload_cli_module()
    store_api_key(_valid_key("B"))

    def _boom(*_args, **_kwargs):
        raise CLIError("backend unavailable")

    monkeypatch.setattr("cli.commands.auth._http_client", _boom)

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["auth", "status"])

    assert result.exit_code == 0
    assert "from keychain" in result.stdout


def test_auth_set_key_warns_when_env_override_active(monkeypatch, in_memory_keyring):
    monkeypatch.setenv("CLI__API_KEY", _valid_key("C"))
    cli_main = _reload_cli_module()

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["auth", "set-key", _valid_key("D")])

    assert result.exit_code == 0
    assert "CLI__API_KEY is set - keychain will be updated but not used" in result.stdout


def test_auth_login_warns_when_env_override_active(monkeypatch, in_memory_keyring):
    monkeypatch.setenv("CLI__API_KEY", _valid_key("E"))
    cli_main = _reload_cli_module()

    @contextmanager
    def _dummy_http_client(*_args, **_kwargs):
        yield object()

    def _fake_start_device_flow(_client, label):
        return {
            "verification_url": "https://example.com/device",
            "user_code": "ABCD-1234",
            "device_code": "device-code",
            "expires_in": 60,
        }

    def _fake_poll_device_status(_client, _device_code, *, deadline, console):
        return _valid_key("F")

    monkeypatch.setattr("cli.commands.auth._http_client", _dummy_http_client)
    monkeypatch.setattr("cli.commands.auth._start_device_flow", _fake_start_device_flow)
    monkeypatch.setattr("cli.commands.auth._poll_device_status", _fake_poll_device_status)
    monkeypatch.setattr("cli.commands.auth.webbrowser.open", lambda *_args, **_kwargs: True)

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["auth", "login", "--no-open-browser"])

    assert result.exit_code == 0
    assert "CLI__API_KEY is set - keychain will be updated but not used" in result.stdout


def test_status_debug_shows_api_key_override(monkeypatch, in_memory_keyring):
    monkeypatch.setenv("CLI__API_KEY", _valid_key("G"))
    monkeypatch.setenv("CTXME_DEBUG", "1")
    cli_main = _reload_cli_module()

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["status"])

    assert result.exit_code == 0
    assert "API Key: Using override (CLI__API_KEY)" in result.stdout
