import logging
from typing import Optional, Type, TypeVar

from pydantic import Field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

logger = logging.getLogger(__name__)

T = TypeVar("T", bound="ETWSettings")

DEFAULTS = {
    "PROCESSCUBE_ENGINE_URL": "http://localhost:56000",
    "PROCESSCUBE_AUTHORITY_URL": "http://localhost:56020",
    "PROCESSCUBE_ETW_CLIENT_ID": "test_etw",
    "PROCESSCUBE_ETW_CLIENT_SECRET": "3ef62eb3-fe49-4c2c-ba6f-73e4d234321b",
    "PROCESSCUBE_ETW_CLIENT_SCOPES": "engine_etw",
    "MAX_GET_OAUTH_ACCESS_TOKEN_RETRIES": 10,
    "ENVIRONMENT": "development",
}


class ETWSettings(BaseSettings):
    """
    Base settings for the External Task Worker library.

    Users can extend this class to add their own settings:

        class MySettings(ETWSettings):
            my_custom_var: str = Field(default="default_value")

        # Initialize with custom settings class
        init_settings(MySettings)
    """

    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    processcube_engine_url: str = Field(default=DEFAULTS["PROCESSCUBE_ENGINE_URL"])
    processcube_authority_url: str = Field(default=DEFAULTS["PROCESSCUBE_AUTHORITY_URL"])
    processcube_etw_client_id: str = Field(default=DEFAULTS["PROCESSCUBE_ETW_CLIENT_ID"])
    processcube_etw_client_secret: str = Field(default=DEFAULTS["PROCESSCUBE_ETW_CLIENT_SECRET"])
    processcube_etw_client_scopes: str = Field(default=DEFAULTS["PROCESSCUBE_ETW_CLIENT_SCOPES"])
    max_get_oauth_access_token_retries: int = Field(default=DEFAULTS["MAX_GET_OAUTH_ACCESS_TOKEN_RETRIES"])
    environment: str = Field(default=DEFAULTS["ENVIRONMENT"])

    @model_validator(mode="before")
    @classmethod
    def warn_missing_values(cls, values: dict) -> dict:

        for env_name, default_value in DEFAULTS.items():
            if env_name not in values or values.get(env_name) is None:
                if default_value is not None:
                    logger.warning(
                        f"Environment variable {env_name} not set, using default: {default_value}"
                    )

        return values


_settings: Optional[ETWSettings] = None


def init_settings(settings_class: Type[T] = ETWSettings) -> T:
    """
    Initialize the global settings instance.

    Call this with a custom settings class to extend the base settings:

        class MySettings(ETWSettings):
            my_var: str = Field(default="value")

        init_settings(MySettings)
    """
    global _settings
    _settings = settings_class()
    return _settings


def get_settings() -> ETWSettings:
    """
    Get the global settings instance.

    If settings haven't been initialized, creates a default ETWSettings instance.
    """
    global _settings
    if _settings is None:
        _settings = ETWSettings()
    return _settings
