"""Configuration management for WLED Screen Controller."""

import os
from pathlib import Path
from typing import List, Literal

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


class ServerConfig(BaseSettings):
    """Server configuration."""

    host: str = "0.0.0.0"
    port: int = 8080
    log_level: str = "INFO"
    cors_origins: List[str] = ["http://localhost:8080"]


class AuthConfig(BaseSettings):
    """Authentication configuration."""

    api_keys: dict[str, str] = {}  # label: key mapping (empty = auth disabled)


class AssetsConfig(BaseSettings):
    """Assets configuration."""

    max_file_size_mb: int = 50          # Max upload size in MB
    assets_dir: str = "data/assets"     # Directory for uploaded asset files


class StorageConfig(BaseSettings):
    """Storage configuration."""

    database_file: str = "data/ledgrab.db"


class MQTTConfig(BaseSettings):
    """MQTT broker configuration."""

    enabled: bool = False
    broker_host: str = "localhost"
    broker_port: int = 1883
    username: str = ""
    password: str = ""
    client_id: str = "ledgrab"
    base_topic: str = "ledgrab"


class LoggingConfig(BaseSettings):
    """Logging configuration."""

    format: Literal["json", "text"] = "json"
    file: str = "logs/wled_controller.log"
    max_size_mb: int = 100
    backup_count: int = 5


class Config(BaseSettings):
    """Main application configuration."""

    model_config = SettingsConfigDict(
        env_prefix="WLED_",
        env_nested_delimiter="__",
        case_sensitive=False,
    )

    demo: bool = False

    server: ServerConfig = Field(default_factory=ServerConfig)
    auth: AuthConfig = Field(default_factory=AuthConfig)
    storage: StorageConfig = Field(default_factory=StorageConfig)
    assets: AssetsConfig = Field(default_factory=AssetsConfig)
    mqtt: MQTTConfig = Field(default_factory=MQTTConfig)
    logging: LoggingConfig = Field(default_factory=LoggingConfig)

    def model_post_init(self, __context: object) -> None:
        """Override storage and assets paths when demo mode is active."""
        if self.demo:
            for field_name in StorageConfig.model_fields:
                value = getattr(self.storage, field_name)
                if isinstance(value, str) and value.startswith("data/"):
                    setattr(self.storage, field_name, value.replace("data/", "data/demo/", 1))
            for field_name in AssetsConfig.model_fields:
                value = getattr(self.assets, field_name)
                if isinstance(value, str) and value.startswith("data/"):
                    setattr(self.assets, field_name, value.replace("data/", "data/demo/", 1))

    @classmethod
    def from_yaml(cls, config_path: str | Path) -> "Config":
        """Load configuration from YAML file.

        Args:
            config_path: Path to YAML configuration file

        Returns:
            Config instance
        """
        config_path = Path(config_path)
        if not config_path.exists():
            raise FileNotFoundError(f"Configuration file not found: {config_path}")

        with open(config_path, "r", encoding="utf-8") as f:
            config_data = yaml.safe_load(f)

        return cls(**config_data)

    @classmethod
    def load(cls) -> "Config":
        """Load configuration from default locations.

        Tries to load from:
        1. Environment variable WLED_CONFIG_PATH
        2. WLED_DEMO=true → ./config/demo_config.yaml (if it exists)
        3. ./config/default_config.yaml
        4. Default values

        Returns:
            Config instance
        """
        config_path = os.getenv("WLED_CONFIG_PATH")

        if config_path:
            return cls.from_yaml(config_path)

        # Demo mode: try dedicated demo config first
        if os.getenv("WLED_DEMO", "").lower() in ("true", "1", "yes"):
            demo_path = Path("config/demo_config.yaml")
            if demo_path.exists():
                return cls.from_yaml(demo_path)

        # Try default location
        default_path = Path("config/default_config.yaml")
        if default_path.exists():
            return cls.from_yaml(default_path)

        # Use defaults
        return cls()


# Global configuration instance
config: Config | None = None


def get_config() -> Config:
    """Get global configuration instance.

    Returns:
        Config instance
    """
    global config
    if config is None:
        config = Config.load()
    return config


def reload_config() -> Config:
    """Reload configuration from file.

    Returns:
        New Config instance
    """
    global config
    config = Config.load()
    return config


def is_demo_mode() -> bool:
    """Check whether the application is running in demo mode."""
    return get_config().demo
