from __future__ import annotations

from typing import Any, Dict, Optional


class _AuthBaseError(Exception):
    """Common base for authentication pipeline errors.

    Every subclass accepts an optional *component* (e.g. ``"vault"``,
    ``"llm"``, ``"database"``) and free-form *detail* dict so that
    callers can inspect structured context without parsing the message
    string.  All existing ``raise XError("msg")`` sites continue to
    work unchanged.
    """

    def __init__(
        self,
        message: str = "",
        *,
        component: Optional[str] = None,
        detail: Optional[Dict[str, Any]] = None,
    ) -> None:
        super().__init__(message)
        self.component = component
        self.detail = detail or {}


class SecretProviderError(_AuthBaseError):
    """Raised when secrets cannot be retrieved or parsed.

    Covers env-var lookups, file reads, Vault API calls, and K8s secret
    fetches.  Callers catch this to distinguish "the secret store is
    unreachable / misconfigured" from other failure modes so they can
    surface actionable operator guidance without leaking secret values.
    """


class ConfigurationError(_AuthBaseError):
    """Raised when configuration is invalid or missing required fields.

    Used during static validation — before any network call is made — to
    reject bad auth_type values, missing mapping keys, or unsupported
    provider strings.  Separating this from runtime errors lets callers
    fail fast with a clear "fix your config" message.
    """


class AuthMaterializationError(_AuthBaseError):
    """Raised when connection credentials cannot be built from secrets.

    Occurs *after* secrets are successfully fetched but the resulting
    values cannot produce a usable connection (e.g. a private key fails
    to parse, a disallowed auth method is requested, or a required
    library is missing).  Distinguishing this from SecretProviderError
    tells operators "your secrets are reachable but the credential
    assembly step failed."
    """


class ValidationError(_AuthBaseError):
    """Raised when a live validation step fails.

    Used by ConnectionManager.validate_*() methods that make real
    outbound calls (SELECT 1, LLM ping, embedding ping).  Separating
    this from materialization errors lets callers report "credentials
    built OK but the service is unreachable / rejected the request."
    """


class MissingConfigError(ConfigurationError):
    """Raised when no configuration source is provided.

    Use when neither a config path nor an env token is supplied.
    """


class RedisConnectionError(_AuthBaseError):
    """Raised when Redis is unreachable or misconfigured."""
