"""Single-source config loader for all Sanad subsystems.

Each subsystem (core, voice, motion, dashboard) has its own JSON file at
`config/<subsystem>_config.json`. This module loads them on demand, caches
the result, and exposes helpers for pulling nested sections.

Usage:
    from Project.Sanad.core.config_loader import load, get

    cfg = load("voice")                         # full voice config dict
    threshold = get("voice", "barge_in.threshold", 500)
    rates = get("voice", "sanad_voice", {})     # whole section

Why JSON (not TOML/YAML): standard library only, editable in any text
editor, commented via "_comment" keys. No third-party dep.
"""

from __future__ import annotations

import json
import logging
import threading
from pathlib import Path
from typing import Any

log = logging.getLogger("config_loader")

# Resolved at first-load time (avoids circular import with config.py)
_BASE_DIR: Path | None = None
_CONFIG_DIR: Path | None = None

_CACHE: dict[str, dict[str, Any]] = {}
_LOCK = threading.Lock()


def _resolve_dirs() -> tuple[Path, Path]:
    """Find Sanad's root and config/ directory (lazy + cached)."""
    global _BASE_DIR, _CONFIG_DIR
    if _BASE_DIR is not None and _CONFIG_DIR is not None:
        return _BASE_DIR, _CONFIG_DIR
    here = Path(__file__).resolve().parent  # Sanad/core
    base = here.parent                      # Sanad/
    _BASE_DIR = base
    _CONFIG_DIR = base / "config"
    return _BASE_DIR, _CONFIG_DIR


def _strip_comments(d: Any) -> Any:
    """Remove top-level "_comment"/"_description" keys — noise for callers."""
    if isinstance(d, dict):
        return {
            k: _strip_comments(v) for k, v in d.items()
            if not (isinstance(k, str) and k.startswith("_"))
        }
    if isinstance(d, list):
        return [_strip_comments(x) for x in d]
    return d


def load(subsystem: str) -> dict[str, Any]:
    """Load + cache config/<subsystem>_config.json.

    Returns a dict with all leading-underscore keys stripped. Missing
    file returns an empty dict (callers supply their own defaults via
    `get(..., default)`).
    """
    with _LOCK:
        if subsystem in _CACHE:
            return _CACHE[subsystem]

        _, cfg_dir = _resolve_dirs()
        path = cfg_dir / f"{subsystem}_config.json"
        if not path.exists():
            log.warning("config file missing: %s — using empty dict", path)
            _CACHE[subsystem] = {}
            return _CACHE[subsystem]

        try:
            raw = json.loads(path.read_text(encoding="utf-8"))
        except json.JSONDecodeError as exc:
            log.error("config file %s unreadable: %s", path, exc)
            _CACHE[subsystem] = {}
            return _CACHE[subsystem]

        cleaned = _strip_comments(raw)
        _CACHE[subsystem] = cleaned
        return cleaned


def get(subsystem: str, dotted_key: str, default: Any = None) -> Any:
    """Fetch a nested key. Supports dotted-paths: 'barge_in.threshold'."""
    cfg = load(subsystem)
    parts = dotted_key.split(".")
    cur: Any = cfg
    for p in parts:
        if not isinstance(cur, dict) or p not in cur:
            return default
        cur = cur[p]
    return cur


def section(subsystem: str, name: str) -> dict[str, Any]:
    """Convenience — load one top-level section, always returning a dict.

    Example: `section("voice", "sanad_voice")` → dict of that section.
    """
    s = get(subsystem, name, {})
    return s if isinstance(s, dict) else {}


def reload(subsystem: str | None = None) -> None:
    """Drop cached config so next load() re-reads from disk."""
    with _LOCK:
        if subsystem is None:
            _CACHE.clear()
        else:
            _CACHE.pop(subsystem, None)


def config_dir() -> Path:
    """Absolute path to Sanad/config/."""
    _, d = _resolve_dirs()
    return d
