from __future__ import annotations

from dataclasses import dataclass
from typing import Mapping, Protocol

from ember.models.providers.utils import ResponsesRequest

from ..domain.admission import AdmissionController
from ..domain.alias import AliasCatalog
from ..domain.errors import NoCapacityError, RateLimitedError
from ..domain.model import Message
from ..ports.auth import AuthContext
from ..ports.billing import BillingStore
from ..ports.creds import CredentialPool
from ..ports.idem import IdempotencyStore
from ..ports.limits import ConcurrencyLimiter, RateLimiter, TPMLimiter
from ..ports.plans import OrgPlanStore
from ..ports.pricing import PricingEngine
from ..ports.providers import ProviderRegistry
from ..ports.replay import ReplayStore
from ..ports.routing import Router
from ..ports.secrets import SecretStore
from ..ports.sur import SurStore
from ..ports.time_uuid import Clock, IdFactory
from .executor import ExecutionResult
from .types import OrgLimits


class TokenEstimator(Protocol):
    def estimate_messages(self, messages: list[Message]) -> int: ...


class ErrorFactory(Protocol):
    def rate_limited(self, *, scope: str, phase: str | None = None) -> RateLimitedError: ...

    def no_capacity(self, *, model: str) -> NoCapacityError: ...


class ExecutorProtocol(Protocol):
    def execute(
        self,
        *,
        org_id: str,
        request_id: str,
        provider: str,
        model: str,
        responses_request: ResponsesRequest,
        prompt_messages: list[Message],
        stream: bool,
        temperature: float | None,
        api_key_override: str | None,
        limits: OrgLimits,
        plan: Mapping[str, object],
    ) -> ExecutionResult: ...


@dataclass
class Settings:
    """Gateway runtime configuration."""

    default_tier: str = "T1"
    sur_dir: str = "tmp/sur"
    enable_judge_stream: bool = False
    rbc_ttl_seconds: int = 300  # 5 minutes; was hardcoded to 120s
    capability_gating: bool = True  # Enable policy enforcement by default
    strict_validation: bool = False  # Reject unknown request fields when True


@dataclass
class Services:
    settings: Settings
    registry: ProviderRegistry
    admission: AdmissionController
    router: Router
    pricing: PricingEngine
    billing: BillingStore
    idem: IdempotencyStore
    secrets: SecretStore
    credentials: CredentialPool
    plans: OrgPlanStore
    tpm: TPMLimiter
    rpm: RateLimiter
    ccy: ConcurrencyLimiter
    replay: ReplayStore
    sur: SurStore
    tokenizer: TokenEstimator
    clock: Clock
    ids: IdFactory
    auth: AuthContext
    alias: AliasCatalog
    executor: ExecutorProtocol
    errors: ErrorFactory
