from __future__ import annotations
import os
from enum import Enum
from typing import Dict, Any, Optional, Union, List
from pydantic import BaseModel, Field, field_validator, ConfigDict

class AuthType(str, Enum):
    BASIC = "basic"
    API_KEY = "api_key"
    OAUTH2 = "oauth2"

class BasicAuthConfig(BaseModel):
    type: AuthType = AuthType.BASIC
    username: str
    password: str

class ApiKeyLocation(str, Enum):
    HEADER = "header"
    QUERY = "query"

class ApiKeyAuthConfig(BaseModel):
    type: AuthType = AuthType.API_KEY
    key: str
    value: str
    in_: ApiKeyLocation = Field(default=ApiKeyLocation.HEADER, alias="in")

    model_config = ConfigDict(populate_by_name=True)

class OAuth2AuthConfig(BaseModel):
    type: AuthType = AuthType.OAUTH2
    client_id: str
    client_secret: str
    token_url: str
    refresh_token: Optional[str] = None
    scopes: List[str] = Field(default_factory=list)
    extra_params: Dict[str, Any] = Field(default_factory=dict)

AuthConfig = Union[BasicAuthConfig, ApiKeyAuthConfig, OAuth2AuthConfig]

class RetryConfig(BaseModel):
    max_retries: int = Field(default=0, alias="maxRetries")
    whitelist: List[str] = Field(default_factory=list)
    blacklist: List[str] = Field(default_factory=list)

    model_config = ConfigDict(populate_by_name=True)

class ClientSettings(BaseModel):
    client_id: str = Field(alias="client_id")
    base_url: str = Field(alias="baseUrl")
    auth: Optional[AuthConfig] = None
    timeout: float = 10.0
    backend: Optional[str] = None
    dsn: Optional[str] = None
    extra: Dict[str, Any] = Field(default_factory=dict)
    
    # Client-wide configuration
    retry: RetryConfig = Field(default_factory=RetryConfig)
    handle_redirects: bool = Field(default=False, alias="handleRedirects")

    model_config = ConfigDict(populate_by_name=True)

class ClientConfigRegistry:
    """
    A read-only registry for client configurations.
    """
    def __init__(self, config_dict: Dict[str, Any]):
        self._clients: Dict[str, ClientSettings] = {}
        clients_data = config_dict.get("clients", {})
        
        for name, settings in clients_data.items():
            # In the new flat model, we just validate the settings directly
            if "client_id" not in settings:
                settings["client_id"] = name
            self._clients[name] = ClientSettings.model_validate(settings)

    def __getitem__(self, key: str) -> ClientSettings:
        if key not in self._clients:
            raise KeyError(f"Client '{key}' not found in configuration.")
        return self._clients[key]

    def get(self, key: str, default: Any = None) -> Optional[ClientSettings]:
        return self._clients.get(key, default)

    def __contains__(self, key: str) -> bool:
        return key in self._clients
