"""Thin wrapper around keyring for API key storage."""

from __future__ import annotations

import os
import sys
from enum import Enum

import keyring
from keyring.errors import KeyringError, PasswordDeleteError

try:
    from shared import ConfigError, validate_api_key_format
except ImportError:
    from cli._vendor.shared import ConfigError, validate_api_key_format

from .exceptions import CLIError, KeyringFailure

SERVICE_NAME = "ctxme"
ACCOUNT_NAME = "api_key"
CLI_API_KEY_ENV = "CLI__API_KEY"


class AuthSource(str, Enum):
    """Enum describing where the API key was sourced from."""

    ENV = "environment"
    KEYCHAIN = "keychain"


def _hint() -> str:
    if sys.platform.startswith("linux"):
        return (
            "Ensure a keyring backend (e.g., gnome-keyring or KWallet) is installed and unlocked."
        )
    if sys.platform == "darwin":
        return "Verify the login Keychain is unlocked."
    if sys.platform.startswith("win"):
        return "Check that the Windows Credential Manager service is running."
    return "Confirm an OS keychain backend is available."


def store_api_key(api_key: str) -> None:
    """Persist API key in the OS keychain."""
    validated = validate_api_key_format(api_key)
    try:
        keyring.set_password(SERVICE_NAME, ACCOUNT_NAME, validated)
    except KeyringError as exc:
        raise KeyringFailure(f"Unable to store API key in the OS keychain. {_hint()}") from exc


def get_api_key() -> str | None:
    """Retrieve stored API key, if any."""
    try:
        return keyring.get_password(SERVICE_NAME, ACCOUNT_NAME)
    except KeyringError as exc:
        raise KeyringFailure(f"Unable to read API key from the OS keychain. {_hint()}") from exc


def get_env_api_key_override() -> str | None:
    """Return API key from CLI__API_KEY, if set and valid."""
    raw_value = os.getenv(CLI_API_KEY_ENV)
    if raw_value is None:
        return None

    stripped = raw_value.strip()
    if not stripped:
        return None

    try:
        return validate_api_key_format(stripped)
    except ConfigError as exc:
        raise CLIError(f"Invalid API key format in {CLI_API_KEY_ENV}: {exc}") from exc


def get_api_key_with_env_override() -> tuple[str | None, AuthSource]:
    """Return API key along with its source (env override or keychain)."""
    env_value = get_env_api_key_override()
    if env_value is not None:
        return env_value, AuthSource.ENV
    return get_api_key(), AuthSource.KEYCHAIN


def delete_api_key() -> None:
    """Remove the stored API key (best-effort)."""
    try:
        keyring.delete_password(SERVICE_NAME, ACCOUNT_NAME)
    except PasswordDeleteError:
        # Already removed or missing.
        return
    except KeyringError as exc:
        raise KeyringFailure(f"Unable to delete API key from the OS keychain. {_hint()}") from exc
