"""Configuration loading for the Pi Multi-FX Pedal.

Loads YAML config with deep-merge over defaults. Separated from
main.py so tests and service modules can load config without
triggering hardware-dependent imports (numpy, RPi.GPIO, etc.).
"""

from __future__ import annotations

import logging
from pathlib import Path

logger = logging.getLogger(__name__)

DEFAULT_CONFIG_PATH = Path.home() / ".pedal" / "config.yaml"

# ── Default configuration ─────────────────────────────────────────────────────

DEFAULT_CONFIG: dict = {
    "audio": {
        "hat_type": "audioinjector",
        "profile": "standard",
        "mode": "mono",
        "input_device": "hw:0,0",
        "output_device": "hw:0,0",
        "jack_enabled": True,
        "auto_connect": True,
    },
    "midi": {
        "uart_port": "/dev/ttyAMA0",
        "usb": True,
    },
    "footswitch": {
        "layout": [
            {"gpio_pin": 17, "action_default": "preset_up", "action_long_press": "tap_tempo"},
            {"gpio_pin": 27, "action_default": "preset_down", "action_long_press": "tuner"},
            {"gpio_pin": 22, "action_default": "bypass", "action_long_press": "snapshot_save"},
            {"gpio_pin": 23, "action_default": "bank_up", "action_long_press": "bank_down"},
        ],
    },
    "leds": {
        "driver": "neopixel",
        "num_leds": 4,
        "pin": "D18",
        "brightness": 0.5,
    },
    "display": {
        "i2c_bus": 1,
        "i2c_addr": 0x3C,
    },
    "presets": {
        "dir": "~/.pedal/presets",
        "install_factory": True,
    },
}


def save_config(cfg: dict, path: Path = DEFAULT_CONFIG_PATH) -> bool:
    """Save config dict to YAML file (preserves existing keys, overwrites in-memory state).

    Returns True on success, False on failure.
    """
    try:
        import yaml
        with open(path, "w") as f:
            yaml.dump(cfg, f, default_flow_style=False)
        logger.info("Saved config to %s", path)
        return True
    except (ImportError, OSError) as e:
        logger.warning("Failed to save config to %s: %s", path, e)
        return False


def load_config(path: Path = DEFAULT_CONFIG_PATH) -> dict:
    """Load config from YAML, merging with defaults for any missing keys."""
    cfg = dict(DEFAULT_CONFIG)  # shallow copy top level

    if path.exists():
        try:
            import yaml
            with open(path, "r") as f:
                overrides = yaml.safe_load(f) or {}
            _deep_merge(cfg, overrides)
            logger.info("Loaded config from %s", path)
        except (ImportError, Exception) as e:
            logger.warning("Failed to load config from %s: %s — using defaults", path, e)
    else:
        logger.info("No config at %s — using defaults. Create one to customize.", path)
        try:
            import yaml
            with open(path, "w") as f:
                yaml.dump(DEFAULT_CONFIG, f, default_flow_style=False)
            logger.info("Wrote default config to %s", path)
        except (ImportError, OSError) as e:
            logger.warning("Could not write default config: %s", e)

    return cfg


def _deep_merge(base: dict, overrides: dict) -> None:
    """Recursively merge overrides into base (mutates base)."""
    for key, val in overrides.items():
        if key in base and isinstance(base[key], dict) and isinstance(val, dict):
            _deep_merge(base[key], val)
        else:
            base[key] = val