"""Gateway settings for OSS builds.

Provides the same dataclass hierarchy as the proprietary settings module
but loads configuration from a local YAML file or environment variables
instead of the Takumi config system.
"""

from __future__ import annotations

import os
from dataclasses import dataclass, field, fields
from functools import lru_cache
from pathlib import Path
from typing import Any

try:
    import yaml

    _HAS_YAML = True
except ImportError:  # pragma: no cover
    _HAS_YAML = False

_LAST_SETTINGS_PATH: Path | None = None


def _coerce_dataclass(dc_cls: type, payload: dict[str, Any] | None) -> Any:
    if payload is None:
        payload = {}
    allowed = {f.name for f in fields(dc_cls)}
    filtered = {k: v for k, v in payload.items() if k in allowed}
    return dc_cls(**filtered)


@dataclass
class AuthSettings:
    mode: str = "memory"
    require_auth: bool = False
    issued_keys: list[str] = field(default_factory=lambda: ["dev-key:org_dev"])
    default_tier: str = "T1"
    dev_default_tier: str = "T3"
    pepper: str = ""
    key_prefix: str = "tkm_sk"


@dataclass
class StoreSettings:
    postgres_dsn: str | None = None
    redis_url: str | None = None
    auto_init: bool = False


@dataclass
class FeatureSettings:
    capability_gating: bool = True
    internal_rate_limiter: bool = False
    model_alias: bool = True
    capability_registry: bool = False


@dataclass
class ProviderSettings:
    openai_keys: list[str] = field(default_factory=list)
    anthropic_keys: list[str] = field(default_factory=list)
    google_keys: list[str] = field(default_factory=list)
    enable_real_adapters: bool = False
    google_streaming: bool | None = None


@dataclass
class AdminSettings:
    token: str | None = None
    sur_dir: str = "tmp/sur"


@dataclass
class LimitSettings:
    """Rate limiting settings for the gateway.

    All limits default to None (unlimited). Production deployments should
    explicitly configure limits via config file. This follows the principle
    that rate limiting should be opt-in, not opt-out - hidden defaults cause
    mysterious failures that are hard to debug.
    """

    rl_capacity: int | None = None
    rl_refill: float | None = None
    default_tpm: int | None = None  # Tokens per minute; None = unlimited


@dataclass
class SecretSettings:
    signing_secret: str | None = None
    previous_signing_secret: str | None = None
    master_key: str | None = None


@dataclass
class ConfigPaths:
    tiers_path: str = str(Path.home() / ".ember" / "tiers.yaml")


@dataclass
class RuntimeSettings:
    region: str = "us-east-1"


@dataclass
class LoggingSettings:
    enabled: bool = True
    path: str | None = None
    level: str = "INFO"


@dataclass
class CloudLoggingSettings:
    """Configuration for cloud log synchronization (GCS)."""

    enabled: bool = False
    gcs_bucket: str | None = None
    gcs_prefix: str = "gateway-logs"
    sync_interval_seconds: int = 60
    batch_size: int = 100


def _load_yaml_config(path: Path | None) -> dict[str, Any]:
    """Load gateway config from a YAML file.

    Falls back to ``~/.ember/gateway.yaml`` when *path* is ``None``.
    Returns an empty dict when the file does not exist or PyYAML is
    unavailable.
    """
    if path is None:
        env_path = os.environ.get("EMBER_GATEWAY_CONFIG")
        if env_path:
            path = Path(env_path)
        else:
            path = Path.home() / ".ember" / "gateway.yaml"

    if not path.exists() or not _HAS_YAML:
        return {}

    with open(path) as f:
        data = yaml.safe_load(f)
    return data if isinstance(data, dict) else {}


@dataclass
class GatewaySettings:
    auth: AuthSettings = field(default_factory=AuthSettings)
    stores: StoreSettings = field(default_factory=StoreSettings)
    features: FeatureSettings = field(default_factory=FeatureSettings)
    providers: ProviderSettings = field(default_factory=ProviderSettings)
    admin: AdminSettings = field(default_factory=AdminSettings)
    limits: LimitSettings = field(default_factory=LimitSettings)
    secrets: SecretSettings = field(default_factory=SecretSettings)
    config: ConfigPaths = field(default_factory=ConfigPaths)
    runtime: RuntimeSettings = field(default_factory=RuntimeSettings)
    logging: LoggingSettings = field(default_factory=LoggingSettings)
    cloud_logging: CloudLoggingSettings = field(default_factory=CloudLoggingSettings)

    @classmethod
    def load(cls, path: Path | None = None) -> "GatewaySettings":
        gateway_data = _load_yaml_config(path)

        return cls(
            auth=_coerce_dataclass(AuthSettings, gateway_data.get("auth")),
            stores=_coerce_dataclass(StoreSettings, gateway_data.get("stores")),
            features=_coerce_dataclass(
                FeatureSettings, gateway_data.get("features")
            ),
            providers=_coerce_dataclass(
                ProviderSettings, gateway_data.get("providers")
            ),
            admin=_coerce_dataclass(AdminSettings, gateway_data.get("admin")),
            limits=_coerce_dataclass(LimitSettings, gateway_data.get("limits")),
            secrets=_coerce_dataclass(
                SecretSettings, gateway_data.get("secrets")
            ),
            config=_coerce_dataclass(ConfigPaths, gateway_data.get("config")),
            runtime=_coerce_dataclass(
                RuntimeSettings, gateway_data.get("runtime")
            ),
            logging=_coerce_dataclass(
                LoggingSettings, gateway_data.get("logging")
            ),
            cloud_logging=_coerce_dataclass(
                CloudLoggingSettings, gateway_data.get("cloud_logging")
            ),
        )


@lru_cache(maxsize=1)
def get_gateway_settings(path: Path | None = None) -> GatewaySettings:
    """Return cached gateway settings, loading from disk on first call."""
    global _LAST_SETTINGS_PATH
    if path is not None:
        _LAST_SETTINGS_PATH = Path(path)
    elif _LAST_SETTINGS_PATH is not None:
        path = _LAST_SETTINGS_PATH

    return GatewaySettings.load(path)


def reload_gateway_settings(path: Path | None = None) -> GatewaySettings:
    """Force reload of gateway settings, clearing any cached value."""

    get_gateway_settings.cache_clear()
    global _LAST_SETTINGS_PATH
    if path is not None:
        _LAST_SETTINGS_PATH = Path(path)
    return get_gateway_settings(path)


__all__ = [
    "AuthSettings",
    "StoreSettings",
    "FeatureSettings",
    "ProviderSettings",
    "AdminSettings",
    "LimitSettings",
    "SecretSettings",
    "ConfigPaths",
    "RuntimeSettings",
    "LoggingSettings",
    "CloudLoggingSettings",
    "GatewaySettings",
    "get_gateway_settings",
    "reload_gateway_settings",
]
