"""Configuration management with TOML config loading and env var resolution."""

from __future__ import annotations

import os
from pathlib import Path
from typing import Any

from pydantic import BaseModel, ConfigDict


class AuthConfig(BaseModel):
    """Authentication configuration."""

    model_config = ConfigDict(extra="allow")

    token: str | None = None
    token_url: str | None = None
    client_id: str | None = None
    client_secret: str | None = None
    passport_broker: str | None = None


class Config(BaseModel):
    """ai4gh configuration with cascading resolution.

    Priority (highest to lowest):
    1. Programmatic (constructor args)
    2. Environment variables (AI4GH_*)
    3. Config file (~/.ai4gh/config.toml)
    4. Profile file (~/.ai4gh/profiles/{name}.toml)
    5. Defaults
    """

    model_config = ConfigDict(extra="allow")

    base_url: str | None = None
    auth: AuthConfig = AuthConfig()
    timeout: float = 30.0
    max_retries: int = 3
    rate_limit: float | None = None
    verify_ssl: bool = True
    profile: str | None = None
    log_level: str = "INFO"

    @classmethod
    def from_env(cls) -> Config:
        """Load configuration from environment variables."""
        env_map: dict[str, Any] = {}
        auth_map: dict[str, Any] = {}

        if v := os.environ.get("AI4GH_BASE_URL"):
            env_map["base_url"] = v
        if v := os.environ.get("AI4GH_TIMEOUT"):
            env_map["timeout"] = float(v)
        if v := os.environ.get("AI4GH_MAX_RETRIES"):
            env_map["max_retries"] = int(v)
        if v := os.environ.get("AI4GH_VERIFY_SSL"):
            env_map["verify_ssl"] = v.lower() not in ("0", "false", "no")
        if v := os.environ.get("AI4GH_PROFILE"):
            env_map["profile"] = v
        if v := os.environ.get("AI4GH_LOG_LEVEL"):
            env_map["log_level"] = v

        if v := os.environ.get("AI4GH_AUTH_TOKEN"):
            auth_map["token"] = v
        if v := os.environ.get("AI4GH_AUTH_TOKEN_URL"):
            auth_map["token_url"] = v
        if v := os.environ.get("AI4GH_AUTH_CLIENT_ID"):
            auth_map["client_id"] = v
        if v := os.environ.get("AI4GH_AUTH_CLIENT_SECRET"):
            auth_map["client_secret"] = v
        if v := os.environ.get("AI4GH_PASSPORT_BROKER"):
            auth_map["passport_broker"] = v

        if auth_map:
            env_map["auth"] = AuthConfig(**auth_map)

        return cls(**env_map)

    @classmethod
    def from_file(cls, path: str | Path) -> Config:
        """Load configuration from a TOML file."""
        try:
            import tomllib  # type: ignore[import-untyped]
        except ModuleNotFoundError:
            import tomli as tomllib  # type: ignore[import-untyped,no-redef]

        filepath = Path(path).expanduser()
        if not filepath.exists():
            return cls()

        with open(filepath, "rb") as f:
            data = tomllib.load(f)

        auth_data = data.pop("auth", {})
        if auth_data:
            data["auth"] = AuthConfig(**auth_data)

        return cls(**data)

    @classmethod
    def load(cls, **overrides: Any) -> Config:
        """Load configuration with full cascade resolution.

        Priority: overrides > env vars > config file > defaults.
        """
        # Start with config file
        config_path = Path("~/.ai4gh/config.toml").expanduser()
        base = cls.from_file(config_path)

        # Layer env vars
        env = cls.from_env()
        merged = base.model_dump(exclude_none=True)
        merged.update(env.model_dump(exclude_none=True))

        # Layer profile if specified
        profile_name = overrides.get("profile") or merged.get("profile")
        if profile_name:
            profile_path = Path(f"~/.ai4gh/profiles/{profile_name}.toml").expanduser()
            if profile_path.exists():
                profile = cls.from_file(profile_path)
                profile_data = profile.model_dump(exclude_none=True)
                merged.update(profile_data)

        # Apply overrides
        merged.update({k: v for k, v in overrides.items() if v is not None})

        return cls(**merged)

    def get_spec_url(self, spec_name: str) -> str | None:
        """Get the base URL for a specific GA4GH spec."""
        env_key = f"AI4GH_{spec_name.upper()}_URL"
        return os.environ.get(env_key) or self.base_url
