from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from .anthropic import AnthropicProvider
from .base import ProviderError
from .gemini import GeminiProvider
from .openai import OpenAIProvider
from .openai_compatible import OpenAICompatibleProvider


_PROVIDER_TYPES = {
    "openai": OpenAIProvider,
    "openai_compatible": OpenAICompatibleProvider,
    "custom": OpenAICompatibleProvider,
    "gemini": GeminiProvider,
    "anthropic": AnthropicProvider,
    "claude": AnthropicProvider,
}


@dataclass(slots=True)
class ProviderRegistry:
    providers: dict[str, Any]
    config: dict[str, Any]

    def get(self, name: str):
        return self.providers[name]

    def list_provider_names(self) -> list[str]:
        return sorted(self.providers)

    async def list_all_models(self) -> dict[str, list[str]]:
        result: dict[str, list[str]] = {}
        for name, provider in self.providers.items():
            result[name] = await provider.list_models()
        return result

    def reload(self, config: dict[str, Any]) -> "ProviderRegistry":
        rebuilt = build_provider_registry(config)
        self.providers = rebuilt.providers
        self.config = rebuilt.config
        return self


def build_provider_registry(config: dict[str, Any]) -> ProviderRegistry:
    providers_cfg = config.get("providers") or {}
    items = providers_cfg.get("items") or providers_cfg
    if not isinstance(items, dict) or not items:
        raise ProviderError("Provider registry config requires a non-empty 'providers.items' mapping")

    built: dict[str, Any] = {}
    for name, raw in items.items():
        if not isinstance(raw, dict):
            raise ProviderError(f"Provider '{name}' config must be a mapping")
        if raw.get("enabled") is False:
            continue
        provider_type = (raw.get("type") or "openai_compatible").strip()
        provider_cls = _PROVIDER_TYPES.get(provider_type)
        if provider_cls is None:
            supported = ", ".join(sorted(_PROVIDER_TYPES))
            raise ProviderError(f"Unsupported provider type '{provider_type}' for '{name}'. Supported: {supported}")

        common_kwargs = {
            "provider_name": name,
            "timeout": raw.get("timeout", 60.0),
        }
        if provider_cls is GeminiProvider:
            built[name] = provider_cls(
                api_key=raw.get("api_key", ""),
                base_url=raw.get("base_url", "https://generativelanguage.googleapis.com/v1beta"),
                **common_kwargs,
            )
            continue

        if provider_cls is AnthropicProvider:
            built[name] = provider_cls(
                api_key=raw.get("api_key", ""),
                base_url=raw.get("base_url", "https://api.anthropic.com/v1"),
                models=raw.get("models") or [],
                **common_kwargs,
            )
            continue

        built[name] = provider_cls(
            api_key=raw.get("api_key", ""),
            base_url=raw.get("base_url", "https://api.openai.com/v1"),
            extra_headers=raw.get("headers") or {},
            **common_kwargs,
        )

    if not built:
        raise ProviderError("No enabled providers configured")
    return ProviderRegistry(providers=built, config=config)
