"""
wivexx_notify_prefs.py — On/off switches for Wivexx's RECURRING notifications.  (v1.0)
═══════════════════════════════════════════════════════════════════════════════
Wivexx fires a handful of *automatic, recurring* spoken notifications — the social
media briefing, the "drive almost full" warning, goal reminders, the startup
greeting.  This module is the single source of truth for whether each one is
allowed to speak.  Each recurring source checks `is_enabled(key)` before firing,
and the GUI (Activity → recurring notifications) flips the switches.

Prefs persist to wivexx_notify_prefs.json next to this file.  An UNSET pref falls
back to its default, so existing behaviour is preserved until the user changes it.

Public API
----------
    is_enabled(key) -> bool
    set_enabled(key, on) -> dict
    list_prefs() -> list[dict]            # for the settings panel
    set_logger(logger)
"""

import json
import os
import threading

_logger = None
_lock = threading.Lock()

# key, label, description, default, live (does toggling take effect immediately,
# or only on the next launch — boot-time notifications are next-launch).
DEFS = [
    {"key": "boot_greeting", "label": "Startup greeting",
     "desc": "Wivexx's spoken hello when it wakes up", "default": True, "live": False},
    {"key": "social_brief", "label": "Social media briefing",
     "desc": "Spoken follower & engagement recap, once per launch", "default": False, "live": False},
    {"key": "drive_full", "label": "Drive almost full",
     "desc": "Warns out loud when a disk crosses ~85% full", "default": True, "live": True},
    {"key": "goal_reminders", "label": "Goal reminders",
     "desc": "Your hourly / daily / weekly goal nudges", "default": True, "live": True},
]
_DEFAULTS = {d["key"]: d["default"] for d in DEFS}

_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                     "wivexx_notify_prefs.json")
_prefs: dict = {}
_loaded = False


def set_logger(logger) -> None:
    global _logger
    _logger = logger


def _load() -> None:
    global _prefs, _loaded
    if _loaded:
        return
    data = {}
    try:
        if os.path.exists(_FILE):
            with open(_FILE, encoding="utf-8") as f:
                raw = json.load(f)
            data = {k: bool(v) for k, v in (raw.get("prefs", raw) or {}).items()
                    if k in _DEFAULTS}
    except Exception as e:
        if _logger:
            _logger.warning("notify_prefs: could not load %s: %s", _FILE, e)
    _prefs = data
    _loaded = True


def _save() -> None:
    try:
        with open(_FILE, "w", encoding="utf-8") as f:
            json.dump({"prefs": _prefs}, f, indent=2)
    except Exception as e:
        if _logger:
            _logger.warning("notify_prefs: could not save %s: %s", _FILE, e)


def is_enabled(key: str) -> bool:
    """True if notification *key* is allowed to speak (pref, else its default)."""
    with _lock:
        _load()
        if key in _prefs:
            return bool(_prefs[key])
    return bool(_DEFAULTS.get(key, True))


def set_enabled(key: str, on: bool) -> dict:
    if key not in _DEFAULTS:
        return {"ok": False, "error": f"unknown notification: {key}"}
    with _lock:
        _load()
        _prefs[key] = bool(on)
        _save()
    if _logger:
        _logger.info("notify_prefs: %s -> %s", key, "on" if on else "off")
    return {"ok": True, "key": key, "enabled": bool(on)}


def list_prefs() -> list:
    with _lock:
        _load()
        return [{"key": d["key"], "label": d["label"], "desc": d["desc"],
                 "live": d["live"],
                 "enabled": bool(_prefs.get(d["key"], d["default"]))}
                for d in DEFS]
