from __future__ import annotations

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

from .config import Config
from .models import UpdateManifest

DEFAULT_SETTINGS: dict[str, Any] = {
    "app_name": "NotifyPulse",
    "active_usecase": "",
    "paused": False,
    "hotkey": "F13",
    "startup_toast": True,
    "notify_sound": True,
    "auto_open_browser": True,
    "minimize_to_tray": True,
    "run_on_startup": False,
    "confirm_delete": True,
    "entry_display_mode": "percent",
    "notification_duration": 5,
    "overlay_opacity": 0.4,
    "overlay_duration": 6,
    "overlay_stretch": False,
    "overlay_monitor": 0,
    "wallpaper_fit": "fill",
    "pwa_bg_blur": 18,
    "pwa_bg_opacity": 0.72,
    "log_max_entries": 100,
    "webui_refresh_ms": 1000,
}

DEFAULT_USECASES: list[dict[str, Any]] = []

DEFAULT_UPDATE_MANIFEST: dict[str, Any] = {
    "windows": UpdateManifest().model_dump(),
}


class JsonStore:
    def __init__(self, data_dir: Path):
        self._data_dir = data_dir
        self._lock = threading.RLock()
        self._settings_file = data_dir / "settings.json"
        self._usecases_file = data_dir / "usecases.json"
        self._update_file = data_dir / "update_manifest.json"
        self._init_defaults()

    def _init_defaults(self) -> None:
        with self._lock:
            self._ensure_file(self._settings_file, DEFAULT_SETTINGS)
            self._ensure_file(self._usecases_file, DEFAULT_USECASES)
            self._ensure_file(self._update_file, DEFAULT_UPDATE_MANIFEST)

    @staticmethod
    def _write_json(path: Path, payload: Any) -> None:
        path.write_text(json.dumps(payload, indent=2), encoding="utf-8")

    def _ensure_file(self, path: Path, payload: Any) -> None:
        if not path.exists():
            self._write_json(path, payload)

    @staticmethod
    def _read_json(path: Path, fallback: Any) -> Any:
        try:
            return json.loads(path.read_text(encoding="utf-8"))
        except Exception:
            return fallback

    def get_settings(self) -> dict[str, Any]:
        with self._lock:
            raw = self._read_json(self._settings_file, {})
            return {**DEFAULT_SETTINGS, **raw}

    def update_settings(self, patch: dict[str, Any]) -> dict[str, Any]:
        with self._lock:
            current = self.get_settings()
            current.update(patch)
            self._write_json(self._settings_file, current)
            return current

    def get_usecases(self) -> list[dict[str, Any]]:
        with self._lock:
            raw = self._read_json(self._usecases_file, DEFAULT_USECASES)
            return raw if isinstance(raw, list) else []

    def set_usecases(self, payload: list[dict[str, Any]]) -> list[dict[str, Any]]:
        with self._lock:
            self._write_json(self._usecases_file, payload)
            return payload

    def get_update_manifest(self, platform: str) -> UpdateManifest:
        with self._lock:
            raw = self._read_json(self._update_file, DEFAULT_UPDATE_MANIFEST)
            platform_raw = raw.get(platform) if isinstance(raw, dict) else None
            if not isinstance(platform_raw, dict):
                return UpdateManifest()
            return UpdateManifest.model_validate(platform_raw)

    def set_update_manifest(self, platform: str, manifest: UpdateManifest) -> None:
        with self._lock:
            raw = self._read_json(self._update_file, DEFAULT_UPDATE_MANIFEST)
            if not isinstance(raw, dict):
                raw = {}
            raw[platform] = manifest.model_dump()
            self._write_json(self._update_file, raw)


Config.ensure_dirs()
store = JsonStore(Config.data_dir)
