"""Application settings for the HIEROMEM API service."""

from __future__ import annotations

from functools import lru_cache
from typing import ClassVar, Optional

import os
from pydantic_settings import BaseSettings as APISettingsBase
from pydantic_settings import SettingsConfigDict

from hieromem_api.vault import read_kv_secret


class APISettings(APISettingsBase):
    """Centralised configuration loaded from environment variables."""

    config_path: str = "configs/default.yaml"
    debug: bool = False
    memory_backend: Optional[str] = None
    pgvector_dsn: Optional[str] = None
    neo4j_uri: Optional[str] = None
    neo4j_user: Optional[str] = None
    neo4j_password: Optional[str] = None
    api_host: str = "127.0.0.1"
    api_port: int = 8000
    cors_allow_origins: str = "*"
    api_key_header: Optional[str] = None
    tenant_registry_path: Optional[str] = None
    default_rate_limit_per_minute: int = 60
    ip_rate_limit_per_minute: int = 120
    rate_limit_burst_multiplier: float = 1.5
    rate_limit_backoff_base_seconds: int = 30
    rate_limit_max_backoff_seconds: int = 900
    default_max_episodes_per_tenant: int = 10_000
    default_max_namespaces_per_tenant: int = 100
    max_query_params: int = 100
    max_query_length: int = 4096
    allowed_content_types: str = (
        "application/json,application/x-www-form-urlencoded,multipart/form-data"
    )
    gzip_minimum_size: int = 1000
    recall_cache_ttl_seconds: int = 300  # Cache TTL for recall results

    model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(
        env_prefix="HIEROMEM_",
        case_sensitive=False,
    )

    # Vault integration
    use_vault: bool = False  # Set to true to load secrets from Vault
    vault_addr: Optional[str] = None
    vault_token: Optional[str] = None
    vault_secret_path: str = "secret/hieromem/"
    vault_api_key_path: str = "secret/hieromem/api_keys"
    vault_encryption_key_path: str = "secret/hieromem/encryption"
    vault_namespace: Optional[str] = None
    vault_client_ttl: int = 300

    # OAuth2/OIDC integration
    oidc_enabled: bool = False
    oidc_issuer: Optional[str] = None
    oidc_audience: Optional[str] = None
    oidc_client_id: Optional[str] = None
    oidc_jwks_url: Optional[str] = None
    oidc_role_claim: str = "role"
    oidc_tenant_claim: str = "tenant"
    oidc_cache_ttl: int = 300

    # Secret values
    encryption_key: Optional[str] = None

    redis_url: Optional[str] = None

    # Stripe billing configuration
    stripe_secret_key: str = ""
    stripe_publishable_key: str = ""
    stripe_webhook_secret: str = ""
    stripe_price_id_pro: str = ""
    stripe_price_id_team: str = ""

    def load_vault_secrets(self):
        """Load secrets from HashiCorp Vault if enabled."""
        if not self.use_vault:
            return
        self.vault_addr = self.vault_addr or os.getenv("VAULT_ADDR")
        self.vault_token = self.vault_token or os.getenv("VAULT_TOKEN")
        self.vault_secret_path = os.getenv("VAULT_SECRET_PATH", self.vault_secret_path)

        if not self.vault_addr or not self.vault_token:
            raise RuntimeError(
                "VAULT_ADDR and VAULT_TOKEN must be set when USE_VAULT is true"
            )

        data = read_kv_secret(self, self.vault_secret_path)

        # Map Vault keys to settings attributes if present
        for key, value in data.items():
            if hasattr(self, key):
                setattr(self, key, value)

        # Optionally load encryption key from Vault for registry encryption
        enc_data = read_kv_secret(self, self.vault_encryption_key_path)
        if enc_data.get("key"):
            self.encryption_key = enc_data["key"]
            os.environ.setdefault("HIEROMEM_ENCRYPTION_KEY", self.encryption_key)


@lru_cache(maxsize=1)
def get_settings() -> APISettings:
    """Return cached application settings, loading Vault secrets if enabled."""
    settings = APISettings()
    settings.load_vault_secrets()
    return settings


__all__ = ["APISettings", "get_settings"]
