"""Global configuration and singleton access for the secrets module."""

from __future__ import annotations

from typing import Literal

from pydantic import BaseModel, Field

from vault.encryption import (
    AESGCMEncryption,
    EncryptionProvider,
    FernetEncryption,
)
from vault.rotation import RotationPolicy
from vault.store import InMemorySecretStore, SecretStore


class SecretsConfig(BaseModel):
    """Configuration for the secrets module."""

    master_key: str = Field(description="Master password used to derive encryption keys")
    encryption_provider: Literal["fernet", "aesgcm"] = "fernet"
    default_rotation_days: int = 90
    auto_rotate: bool = False

    model_config = {"arbitrary_types_allowed": True}


class _SecretsContainer:
    """Holds the initialised store, encryption provider, and rotation policy."""

    def __init__(
        self,
        config: SecretsConfig,
        encryption: EncryptionProvider,
        store: SecretStore,
        rotation_policy: RotationPolicy,
    ) -> None:
        self.config = config
        self.encryption = encryption
        self.store = store
        self.rotation_policy = rotation_policy


_instance: _SecretsContainer | None = None


def init_secrets(
    config: SecretsConfig,
    *,
    store: SecretStore | None = None,
    encryption: EncryptionProvider | None = None,
) -> _SecretsContainer:
    """Initialise the secrets module. Call once at application startup.

    Parameters
    ----------
    config:
        Core configuration (master key, provider choice, rotation days).
    store:
        Optional custom store.  Defaults to ``InMemorySecretStore``.
    encryption:
        Optional custom encryption provider.  Defaults to the provider
        named in *config.encryption_provider*.
    """
    global _instance

    if encryption is None:
        if config.encryption_provider == "aesgcm":
            encryption = AESGCMEncryption(master_password=config.master_key)
        else:
            encryption = FernetEncryption(master_password=config.master_key)

    if store is None:
        store = InMemorySecretStore(encryption)

    rotation_policy = RotationPolicy(
        max_age_days=config.default_rotation_days,
        auto_rotate=config.auto_rotate,
    )

    _instance = _SecretsContainer(
        config=config,
        encryption=encryption,
        store=store,
        rotation_policy=rotation_policy,
    )
    return _instance


def get_secrets() -> _SecretsContainer:
    """Return the initialised secrets container.

    Raises ``RuntimeError`` if ``init_secrets()`` has not been called.
    """
    if _instance is None:
        raise RuntimeError("Secrets not initialised. Call init_secrets(config) first.")
    return _instance


def reset_secrets() -> None:
    """Tear down the global instance (useful in tests)."""
    global _instance
    _instance = None
