from typing import Annotated, Generic, List, Literal, Union

from agentic_chat_ui.src.constants import CONFIG_PATH, TCAgentClient, TCView
from pydantic import Field, PositiveInt, SecretStr
from pydantic_settings import (
    BaseSettings,
    PydanticBaseSettingsSource,
    SettingsConfigDict,
    YamlConfigSettingsSource,
)


class FromConfigMixinSettings(BaseSettings):
    module_path: str
    model_config = SettingsConfigDict(yaml_file=CONFIG_PATH, extra="ignore")

    @classmethod
    def settings_customise_sources(
        cls,
        settings_cls: type[BaseSettings],
        init_settings: PydanticBaseSettingsSource,
        env_settings: PydanticBaseSettingsSource,
        dotenv_settings: PydanticBaseSettingsSource,
        file_secret_settings: PydanticBaseSettingsSource,
    ) -> tuple[PydanticBaseSettingsSource, ...]:
        return (
            init_settings,
            YamlConfigSettingsSource(settings_cls),
            env_settings,
            dotenv_settings,
            file_secret_settings,
        )


# ---------------------------------------------------------------------------
# Agent-specific settings
# ---------------------------------------------------------------------------
class AgentClientSettings(FromConfigMixinSettings):
    pass


class ApiAgentClientSettings(AgentClientSettings):
    api_url: str = Field(description="Agent backend endpoint.")
    request_timeout: PositiveInt = Field(description="Timeout in seconds for backend calls.")


# ---------------------------------------------------------------------------
# Controller-specific settings
# ---------------------------------------------------------------------------
class ControllerSettings(FromConfigMixinSettings, Generic[TCAgentClient]):
    agent_client: TCAgentClient


class ViewSettings(BaseSettings):
    pass


class ChainlitCallBackRegistrarSettings(BaseSettings):
    module_path: str
    type: Literal["chat", "auth"]


class ChatChainlitCallBackRegistrarSettings(ChainlitCallBackRegistrarSettings):
    type: Literal["chat"] = "chat"


class AuthChainlitCallBackRegistrarSettings(ChainlitCallBackRegistrarSettings):
    type: Literal["auth"] = "auth"
    users: SecretStr
    model_config = SettingsConfigDict(env_prefix='CHAINLIT_AUTH_', extra="ignore")


ChainlitCallbackSettings = Annotated[
    Union[
        ChatChainlitCallBackRegistrarSettings,
        AuthChainlitCallBackRegistrarSettings,
    ],
    Field(discriminator="type"),
]


class ChainlitViewSettings(ViewSettings):
    callbacks: List[ChainlitCallbackSettings]


# ---------------------------------------------------------------------------
# View-specific settings
# ---------------------------------------------------------------------------
class ViewRunnerSettings(FromConfigMixinSettings, Generic[TCAgentClient, TCView]):
    host: str
    port: int
    controller: ControllerSettings[TCAgentClient]
    view: TCView


class ChainlitViewRunnerRunnerSettings(ViewRunnerSettings[ApiAgentClientSettings, ChainlitViewSettings]):
    pass


class GradioViewRunnerRunnerSettings(ViewRunnerSettings[ApiAgentClientSettings, ViewSettings]):
    pass
