from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings, SettingsConfigDict
from redis import ConnectionError, Redis

from .dav.webdav import Settings as WebDAVSettings
from .dav.webdav import WebDAV


class Credentials(BaseModel):
    username: str = ""
    password: str = ""


class DavSettings(BaseModel):
    """
    Connection to a DAV server.
    """

    protocol: str = "https"
    host: str = "example.com"
    path: str = "/remote.php/webdav"
    prefix: str = "/advent22"

    auth: Credentials = Credentials(
        username="advent22_user",
        password="password",
    )

    config_filename: str = "config.toml"

    @property
    def url(self) -> str:
        """
        Combined DAV URL.
        """

        return f"{self.protocol}://{self.host}{self.path}{self.prefix}"


class RedisSettings(BaseModel):
    """
    Connection to a redis server.
    """

    cache_ttl: int = 60 * 10

    host: str = "localhost"
    port: int = 6379
    db: int = 0
    protocol_version: int = 3


class Settings(BaseSettings):
    """
    Per-run settings.
    """

    model_config = SettingsConfigDict(
        env_prefix="ADVENT22__",
        env_file="api.conf",
        env_file_encoding="utf-8",
        env_nested_delimiter="__",
    )

    #####
    # general settings
    #####

    production_mode: bool = False
    show_api_docs: bool = Field(
        default_factory=lambda data: not data["production_mode"]
    )
    ui_directory: str = "/opt/advent22/ui"

    #####
    # openapi settings
    #####

    def __api_docs[T](self, value: T) -> T | None:
        if self.show_api_docs:
            return value

        return None

    @property
    def openapi_url(self) -> str | None:
        return self.__api_docs("/api/openapi.json")

    @property
    def docs_url(self) -> str | None:
        return self.__api_docs("/api/docs")

    @property
    def redoc_url(self) -> str | None:
        return self.__api_docs("/api/redoc")

    #####
    # webdav settings
    #####

    webdav: DavSettings = DavSettings()
    redis: RedisSettings = RedisSettings()


SETTINGS = Settings()

try:
    _REDIS = Redis(
        host=SETTINGS.redis.host,
        port=SETTINGS.redis.port,
        db=SETTINGS.redis.db,
        protocol=SETTINGS.redis.protocol_version,
    )
    _REDIS.ping()

except ConnectionError:
    raise RuntimeError("Redis connection failed!")


WEBDAV = WebDAV(
    WebDAVSettings(
        url=SETTINGS.webdav.url,
        username=SETTINGS.webdav.auth.username,
        password=SETTINGS.webdav.auth.password,
    ),
    _REDIS,
    SETTINGS.redis.cache_ttl,
)
