"""
Configuration manager for persistent settings.
"""

import os
from pathlib import Path
from typing import Any, Optional

import yaml

from airctl.common.logging import get_logger
from airctl.config.defaults import DEFAULT_PRESETS, get_default_config, get_default_config_path

logger = get_logger(__name__)


class ConfigManager:
    """
    Manages persistent configuration.
    
    Handles device aliases, presets, and daemon settings.
    """

    def __init__(self, config_path: Optional[str] = None):
        """
        Initialize configuration manager.

        Args:
            config_path: Path to config file (default: ~/.airctl/config.yaml)
        """
        self.config_path = config_path or get_default_config_path()
        self._config: dict[str, Any] = {}
        self._load()

    def _load(self) -> None:
        """Load configuration from file."""
        if os.path.exists(self.config_path):
            try:
                with open(self.config_path, "r") as f:
                    self._config = yaml.safe_load(f) or {}
                logger.debug(f"Loaded config from {self.config_path}")
            except Exception as e:
                logger.warning(f"Failed to load config: {e}")
                self._config = get_default_config()
        else:
            self._config = get_default_config()
            self._ensure_config_dir()
            self._save()

    def _save(self) -> None:
        """Save configuration to file."""
        self._ensure_config_dir()
        try:
            with open(self.config_path, "w") as f:
                yaml.dump(self._config, f, default_flow_style=False)
            logger.debug(f"Saved config to {self.config_path}")
        except Exception as e:
            logger.error(f"Failed to save config: {e}")

    def _ensure_config_dir(self) -> None:
        """Ensure configuration directory exists."""
        config_dir = os.path.dirname(self.config_path)
        if config_dir:
            Path(config_dir).mkdir(parents=True, exist_ok=True)

    def get(self, key: str, default: Any = None) -> Any:
        """
        Get a configuration value.

        Args:
            key: Configuration key (supports dot notation)
            default: Default value if key not found

        Returns:
            Configuration value
        """
        keys = key.split(".")
        value = self._config

        for k in keys:
            if isinstance(value, dict) and k in value:
                value = value[k]
            else:
                return default

        return value

    def set(self, key: str, value: Any, save: bool = True) -> None:
        """
        Set a configuration value.

        Args:
            key: Configuration key (supports dot notation)
            value: Value to set
            save: Whether to save to file immediately
        """
        keys = key.split(".")
        config = self._config

        for k in keys[:-1]:
            if k not in config:
                config[k] = {}
            config = config[k]

        config[keys[-1]] = value

        if save:
            self._save()

    def get_aliases(self) -> dict[str, str]:
        """
        Get all device aliases.

        Returns:
            Dict mapping alias -> address
        """
        return self._config.get("aliases", {})

    def get_address_by_alias(self, alias: str) -> Optional[str]:
        """
        Get device address by alias.

        Args:
            alias: Device alias

        Returns:
            Device address or None
        """
        return self._config.get("aliases", {}).get(alias)

    def set_alias(self, address: str, alias: str) -> None:
        """
        Set device alias.

        Args:
            address: Device address
            alias: Alias to set
        """
        if "aliases" not in self._config:
            self._config["aliases"] = {}
        self._config["aliases"][alias] = address
        self._save()
        logger.info(f"Set alias '{alias}' for device {address}")

    def remove_alias(self, alias: str) -> bool:
        """
        Remove device alias.

        Args:
            alias: Alias to remove

        Returns:
            True if alias was removed
        """
        if alias in self._config.get("aliases", {}):
            del self._config["aliases"][alias]
            self._save()
            logger.info(f"Removed alias '{alias}'")
            return True
        return False

    def get_preset(self, name: str) -> Optional[dict[str, str]]:
        """
        Get a preset configuration.

        Args:
            name: Preset name

        Returns:
            Preset configuration or None
        """
        presets = self._config.get("presets", {})
        if name in presets:
            return presets[name]
        if name in DEFAULT_PRESETS:
            return DEFAULT_PRESETS[name]
        return None

    def set_preset(self, name: str, config: dict[str, str]) -> None:
        """
        Set a preset configuration.

        Args:
            name: Preset name
            config: Preset configuration
        """
        if "presets" not in self._config:
            self._config["presets"] = {}
        self._config["presets"][name] = config
        self._save()
        logger.info(f"Set preset '{name}'")

    def remove_preset(self, name: str) -> bool:
        """
        Remove a preset configuration.

        Args:
            name: Preset name

        Returns:
            True if preset was removed
        """
        if name in self._config.get("presets", {}):
            del self._config["presets"][name]
            self._save()
            logger.info(f"Removed preset '{name}'")
            return True
        return False

    def list_presets(self) -> dict[str, dict[str, str]]:
        """
        List all presets (user-defined and default).

        Returns:
            Dict of preset name -> configuration
        """
        presets = dict(DEFAULT_PRESETS)
        presets.update(self._config.get("presets", {}))
        return presets

    def get_daemon_config(self) -> dict[str, Any]:
        """
        Get daemon configuration.

        Returns:
            Daemon configuration dict
        """
        return self._config.get("daemon", get_default_config()["daemon"])

    def set_daemon_config(self, config: dict[str, Any]) -> None:
        """
        Set daemon configuration.

        Args:
            config: Daemon configuration
        """
        self._config["daemon"] = config
        self._save()

    def reset(self) -> None:
        """Reset configuration to defaults."""
        self._config = get_default_config()
        self._save()
        logger.info("Configuration reset to defaults")

    def get_all(self) -> dict[str, Any]:
        """
        Get all configuration.

        Returns:
            Complete configuration dict
        """
        return dict(self._config)
