from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from ..admission import AdmissionController
from ..billing import Pricing, default_pricing
from ..config import GatewayConfig
from ..credentials import CredentialStore, InMemoryCredentialStore
from ..credentials.pool import ProviderPoolV2
from ..pricing import OrgPlanCache
from ..provider_pool import ProviderPool
from ..providers import ProviderAdapter, default_adapters
from ..routing import Router, RouterLiteAdapter
from ..secrets import DevKmsStore, InMemorySecretStore, SecretStore
from ..settings import GatewaySettings, get_gateway_settings, reload_gateway_settings
from ..stores import BillingStore, IdempotencyStore
from ..streaming import InMemoryReplayStore, RedisReplayStore, ReplayStore, StreamCoordinator
from . import GatewayRuntime
from .services import GatewayServices, configure_gateway_services

_ACTIVE_CONTEXT: GatewayRuntimeContext | None = None


def get_active_gateway_context() -> GatewayRuntimeContext | None:
    """Return the most recently bootstrapped or reloaded gateway context."""

    return _ACTIVE_CONTEXT


@dataclass
class GatewayRuntimeContext:
    config: GatewayConfig
    settings: GatewaySettings
    runtime: GatewayRuntime
    billing_store: BillingStore
    idempotency_store: IdempotencyStore
    secret_store: SecretStore
    credential_store: CredentialStore
    replay_store: ReplayStore
    stream_coordinator: StreamCoordinator
    adapters: dict[str, ProviderAdapter]
    admission: AdmissionController
    pricing: Pricing
    provider_pool: ProviderPool
    provider_pool_v2: ProviderPoolV2
    router: Router
    plan_cache: OrgPlanCache


def _init_secret_store(settings: GatewaySettings) -> SecretStore:
    master_key = settings.secrets.master_key
    if master_key:
        return DevKmsStore(master_key)
    return InMemorySecretStore()


def _build_context(
    settings: GatewaySettings,
    config: GatewayConfig | None = None,
) -> GatewayRuntimeContext:
    cfg = config or GatewayConfig.from_settings(settings)
    runtime = GatewayRuntime(cfg, settings=settings)
    secret_store = _init_secret_store(settings)
    cred_store = InMemoryCredentialStore(secret_store)
    if cfg.redis_url:
        try:
            import redis  # type: ignore

            client = redis.Redis.from_url(cfg.redis_url)
            replay_store: ReplayStore = RedisReplayStore(client)
        except Exception as exc:
            raise RuntimeError("Failed to initialize Redis replay store") from exc
    else:
        replay_store = InMemoryReplayStore()
    coordinator = StreamCoordinator(replay_store)
    pricing = default_pricing()
    adapters = default_adapters()
    admission = AdmissionController()
    provider_pool = ProviderPool(settings=settings)
    provider_pool_v2 = ProviderPoolV2(cred_store)
    router = RouterLiteAdapter()
    plan_cache = OrgPlanCache(
        runtime.billing_store.get_org_plan,
        default_tier=settings.auth.default_tier,
    )

    return GatewayRuntimeContext(
        config=cfg,
        settings=settings,
        runtime=runtime,
        billing_store=runtime.billing_store,
        idempotency_store=runtime.idem_store,
        secret_store=secret_store,
        credential_store=cred_store,
        replay_store=replay_store,
        stream_coordinator=coordinator,
        adapters=adapters,
        admission=admission,
        pricing=pricing,
        provider_pool=provider_pool,
        provider_pool_v2=provider_pool_v2,
        router=router,
        plan_cache=plan_cache,
    )


def _configure_services(context: GatewayRuntimeContext) -> None:
    services = GatewayServices(
        adapters=context.adapters,
        admission=context.admission,
        billing_store=context.runtime.billing_store,
        idempotency_store=context.runtime.idem_store,
        pricing=context.pricing,
        provider_pool=context.provider_pool,
        provider_pool_v2=context.provider_pool_v2,
        credential_store=context.credential_store,
        secret_store=context.secret_store,
        router=context.router,
        plan_cache=context.plan_cache,
    )
    configure_gateway_services(services)


def bootstrap_gateway(
    config: GatewayConfig | None = None,
    settings: GatewaySettings | None = None,
) -> GatewayRuntimeContext:
    if settings is None and config is not None and config.settings is not None:
        settings = config.settings

    settings = settings or get_gateway_settings()
    context = _build_context(settings, config=config)
    _configure_services(context)
    global _ACTIVE_CONTEXT
    _ACTIVE_CONTEXT = context
    return context


def reload_gateway_runtime(path: Path | None = None) -> GatewayRuntimeContext:
    settings = reload_gateway_settings(path)
    context = _build_context(settings)
    _configure_services(context)
    global _ACTIVE_CONTEXT
    _ACTIVE_CONTEXT = context
    return context


__all__ = [
    "GatewayRuntimeContext",
    "bootstrap_gateway",
    "reload_gateway_runtime",
    "get_active_gateway_context",
]
