"""Persisted user settings: which quads are enabled, per-module feature toggles,
and quad ordering. Single JSON file, read at startup, written on every change.

Modules never import this directly for their own feature flags; they receive a
scoped view via ctx.feature(...) so the persistence format stays centralised.
"""

from __future__ import annotations

import json
from typing import Callable

from paths import CONFIG_DIR, SETTINGS_FILE, ensure_dirs


class Settings:
    def __init__(self) -> None:
        self._data: dict = {"quads": {}, "features": {}, "order": None, "favorites": []}
        self._listeners: list[Callable[[], None]] = []
        self.load()

    # -- persistence -------------------------------------------------------
    def load(self) -> None:
        path = SETTINGS_FILE
        if not path.exists():
            # one-time migration from the old CONFIG_DIR location (pre state-dir)
            legacy = CONFIG_DIR / "settings.json"
            if legacy.exists():
                path = legacy
        try:
            self._data.update(json.loads(path.read_text()))
        except (FileNotFoundError, json.JSONDecodeError):
            pass

    def save(self) -> None:
        ensure_dirs()
        SETTINGS_FILE.write_text(json.dumps(self._data, indent=2))
        for cb in list(self._listeners):
            cb()

    def subscribe(self, cb: Callable[[], None]) -> None:
        self._listeners.append(cb)

    # -- quad enable/disable ----------------------------------------------
    def quad_enabled(self, module_id: str, default: bool = True) -> bool:
        return bool(self._data["quads"].get(module_id, default))

    def set_quad_enabled(self, module_id: str, value: bool) -> None:
        self._data["quads"][module_id] = bool(value)
        self.save()

    # -- per-module feature toggles ---------------------------------------
    def feature(self, module_id: str, feature_id: str, default: bool = True) -> bool:
        return bool(self._data["features"].get(module_id, {}).get(feature_id, default))

    def set_feature(self, module_id: str, feature_id: str, value: bool) -> None:
        self._data["features"].setdefault(module_id, {})[feature_id] = bool(value)
        self.save()

    # -- favorites ---------------------------------------------------------
    def favorites(self) -> list[str]:
        return list(self._data.get("favorites", []))

    def is_favorite(self, entry: str) -> bool:
        return entry in self._data.get("favorites", [])

    def toggle_favorite(self, entry: str) -> None:
        if not entry:
            return
        favs = self._data.setdefault("favorites", [])
        if entry in favs:
            favs.remove(entry)
        else:
            favs.append(entry)
        self.save()

    # -- ordering ----------------------------------------------------------
    def order(self) -> list[str] | None:
        return self._data.get("order")

    def set_order(self, order: list[str]) -> None:
        self._data["order"] = order
        self.save()
