# modules/common/settings.py
import os
from typing import Any, Dict, Iterable, Optional


def _clean(s: Optional[str]) -> str:
    s = (s or "").strip()
    # strip accidental quotes Portainer sometimes adds
    if (s.startswith('"') and s.endswith('"')) or (s.startswith("'") and s.endswith("'")):
        s = s[1:-1].strip()
    return s


def _collect_shai_env() -> Dict[str, str]:
    """
    Build a {key_without_prefix_lower: cleaned_value} mapping
    from all environment variables that start with SHAI_.
    """
    out: Dict[str, str] = {}
    for k, v in os.environ.items():
        if not k.startswith("SHAI_"):
            continue
        key = k[5:].lower()  # SHAI_MOD_CHANNEL_ID -> mod_channel_id
        out[key] = _clean(v)
    return out


class ConfigView:
    """
    Unified config view.
    - Primary: SHAI_* envs (prefix removed, lowercased keys)
    - Secondary: bot.config['DEFAULT'] (if present)
    - Helpers: get/int/bool/float/list
    - Can mirror values back into os.environ as SHAI_* (opt-in)
    """
    def __init__(self, bot=None, *, mirror_to_env: bool = False):
        self._env_map = _collect_shai_env()

        # Optional: also look into bot.config['DEFAULT'] as a fallback
        self._default: Dict[str, Any] = {}
        try:
            self._default = (getattr(bot, "config", {}) or {}).get("DEFAULT", {}) or {}
        except Exception:
            self._default = {}

        if mirror_to_env:
            # Ensure os.environ has SHAI_* for everything we know (don’t clobber existing non-empty)
            for k, v in self._env_map.items():
                env_key = f"SHAI_{k.upper()}"
                if not os.environ.get(env_key):
                    os.environ[env_key] = v

    # ---- core accessors ----
    def get(self, key: str, default: str = "") -> str:
        key = key.lower()
        if key in self._env_map:
            v = _clean(self._env_map[key])
            return v if v != "" else default

        # Fallback to DEFAULT mapping (ConfigParser-like or our shim)
        try:
            v = self._default.get(key, "")
        except Exception:
            v = ""
        v = _clean(str(v))
        return v if v != "" else default

    def int(self, key: str, default: int = 0) -> int:
        s = self.get(key, "")
        try:
            return int(s)
        except Exception:
            return default

    def float(self, key: str, default: float = 0.0) -> float:
        s = self.get(key, "")
        try:
            return float(s)
        except Exception:
            return default

    def bool(self, key: str, default: bool = False) -> bool:
        s = self.get(key, "")
        if s == "":
            return default
        s = s.lower()
        if s in ("1", "true", "yes", "on", "y", "t"):
            return True
        if s in ("0", "false", "no", "off", "n", "f"):
            return False
        return default

    def list(self, key: str, default: Optional[Iterable[str]] = None, sep: str = ",") -> Iterable[str]:
        s = self.get(key, "")
        if s == "":
            return list(default or [])
        parts = [p.strip() for p in s.split(sep)]
        return [p for p in parts if p]

    # expose the resolved map if you ever want to dump it for debug
    def to_dict(self) -> Dict[str, str]:
        d = dict(self._env_map)
        # Include defaults that aren’t already in env_map
        for k in getattr(self._default, "keys", lambda: [])():
            d.setdefault(k, _clean(str(self._default.get(k, ""))))
        return d


def cfg(bot=None, *, mirror_to_env: bool = False) -> ConfigView:
    """
    Usage in cogs:
        r = cfg(bot)
        trigger_id = r.int('trigger_channel_id', 0)
        prefix = r.get('vc_name_prefix', 'Room')

    If you want to also ensure SHAI_* are present in os.environ at runtime:
        r = cfg(bot, mirror_to_env=True)
    """
    return ConfigView(bot, mirror_to_env=mirror_to_env)
