"""Configuration management for CLI.

Loads configuration with hierarchy: CLI flags > Environment variables > Config file
"""

import os

from pydantic import BaseModel, Field, field_validator

from cli.infrastructure.auth_storage import load_credentials


# Global storage for CLI flag overrides (set by main.py callback)
_global_api_url: str | None = None
_global_api_key: str | None = None


def set_global_overrides(
    api_url: str | None = None, api_key: str | None = None
) -> None:
    """Set global CLI flag overrides.

    Called by the main app callback to store --api-url and --api-key flags.

    Args:
        api_url: Global --api-url flag value
        api_key: Global --api-key flag value
    """
    global _global_api_url, _global_api_key
    _global_api_url = api_url
    _global_api_key = api_key


def get_api_url(default: str = "http://localhost:8000") -> str:
    """Get API URL using the configuration hierarchy.

    Precedence order (highest to lowest):
    1. Global CLI flag (--api-url)
    2. Environment variable (ALLOY_RUNTIME_API_URL)
    3. Config file (~/.alloy-runtime/config)
    4. Default value

    Args:
        default: Fallback value if no configuration source provides URL

    Returns:
        API URL string

    Example:
        api_url = get_api_url()  # Uses hierarchy with localhost default
    """
    # Try global flag (highest priority)
    if _global_api_url:
        return _global_api_url

    # Try environment variable
    env_url = os.environ.get("ALLOY_RUNTIME_API_URL")
    if env_url:
        return env_url

    # Try config file
    file_config = load_credentials()
    if file_config:
        return file_config[0]

    # Use default
    return default


class CLIConfig(BaseModel):
    """CLI configuration with hierarchical loading.

    Precedence order (highest to lowest):
    1. CLI flags (--api-key, --api-url)
    2. Environment variables (ALLOY_RUNTIME_API_KEY, ALLOY_RUNTIME_API_URL)
    3. Config file (~/.alloy-runtime/config)
    """

    api_url: str = Field(..., description="Alloy Runtime server base URL")
    api_key: str = Field(..., description="API authentication key")
    timeout: float | None = Field(
        default=None, description="Request timeout in seconds"
    )

    @field_validator("api_url")
    @classmethod
    def validate_api_url(cls, v: str) -> str:
        """Ensure API URL is non-empty and properly formatted."""
        _ = cls  # Required by Pydantic validator
        if not v or not v.strip():
            raise ValueError("API URL cannot be empty")
        return v.rstrip("/")  # Remove trailing slash

    @field_validator("api_key")
    @classmethod
    def validate_api_key(cls, v: str) -> str:
        """Ensure API key is non-empty."""
        _ = cls  # Required by Pydantic validator
        if not v or not v.strip():
            raise ValueError("API key cannot be empty")
        return v


class ConfigurationError(Exception):
    """Raised when configuration cannot be loaded."""

    pass


def load_config() -> CLIConfig:
    """Load CLI configuration with hierarchical precedence.

    Precedence order (highest to lowest):
    1. Global CLI flags (--api-key, --api-url set via callback)
    2. Environment variables (ALLOY_RUNTIME_API_KEY, ALLOY_RUNTIME_API_URL)
    3. Config file (~/.alloy-runtime/config)

    Returns:
        Validated CLI configuration

    Raises:
        ConfigurationError: If no configuration source provides required values

    Example:
        # Load with hierarchy
        config = load_config()

        # CLI usage:
        alloy --api-url https://prod.example.com admin sync models
        alloy --api-key sk_prod_... credentials update <id>
    """
    # Load from config file (lowest priority)
    file_config = load_credentials()
    api_url_from_file = file_config[0] if file_config else None
    api_key_from_file = file_config[1] if file_config else None

    # Load from environment variables (middle priority)
    api_url_from_env = os.environ.get("ALLOY_RUNTIME_API_URL")
    api_key_from_env = os.environ.get("ALLOY_RUNTIME_API_KEY")

    # Apply hierarchy: Global CLI flags > env vars > config file
    # Note: Must check "is not None" because flags can be explicitly None when not passed
    if _global_api_url is not None:
        api_url = _global_api_url
    elif api_url_from_env:
        api_url = api_url_from_env
    else:
        api_url = api_url_from_file

    if _global_api_key is not None:
        api_key = _global_api_key
    elif api_key_from_env:
        api_key = api_key_from_env
    else:
        api_key = api_key_from_file

    # Validate that we have the required configuration
    if not api_url:
        raise ConfigurationError(
            "API URL not configured. Please provide via:\n"
            "  1. CLI flag: --api-url http://localhost:8000\n"
            "  2. Environment variable: ALLOY_RUNTIME_API_URL\n"
            "  3. Login first: alloy login"
        )

    if not api_key:
        raise ConfigurationError(
            "API key not configured. Please provide via:\n"
            "  1. CLI flag: --api-key sk_live_...\n"
            "  2. Environment variable: ALLOY_RUNTIME_API_KEY\n"
            "  3. Login first: alloy login"
        )

    # Load optional timeout
    timeout = None
    timeout_str = os.environ.get("ALLOY_RUNTIME_TIMEOUT")
    if timeout_str:
        try:
            timeout = float(timeout_str)
        except ValueError:
            raise ConfigurationError(
                "ALLOY_RUNTIME_TIMEOUT must be a valid number (seconds)"
            )

    try:
        return CLIConfig(api_url=api_url, api_key=api_key, timeout=timeout)
    except ValueError as e:
        raise ConfigurationError(f"Invalid configuration: {e}")
