import 'dart:convert';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';

// ── Generic SharedPreferences-backed bool notifier ──────────────────────────

class BoolPref extends StateNotifier<bool> {
  final String _key;

  BoolPref(this._key, bool defaultValue) : super(defaultValue) {
    _load(defaultValue);
  }

  Future<void> _load(bool def) async {
    final p = await SharedPreferences.getInstance();
    if (mounted) state = p.getBool(_key) ?? def;
  }

  Future<void> set(bool v) async {
    state = v;
    final p = await SharedPreferences.getInstance();
    await p.setBool(_key, v);
  }

  void toggle() => set(!state);
}

// ── Generic SharedPreferences-backed String-Set notifier ───────────────────

class StringSetPref extends StateNotifier<Set<String>> {
  final String _key;

  StringSetPref(this._key) : super({}) {
    _load();
  }

  Future<void> _load() async {
    final p = await SharedPreferences.getInstance();
    final list = p.getStringList(_key);
    if (mounted && list != null) state = list.toSet();
  }

  Future<void> add(String v) async {
    if (state.contains(v)) return;
    state = {...state, v};
    final p = await SharedPreferences.getInstance();
    await p.setStringList(_key, state.toList());
  }

  Future<void> remove(String v) async {
    if (!state.contains(v)) return;
    state = {...state}..remove(v);
    final p = await SharedPreferences.getInstance();
    await p.setStringList(_key, state.toList());
  }
}

// ── Notification preferences ─────────────────────────────────────────────────

final notifDesktopProvider =
    StateNotifierProvider<BoolPref, bool>((ref) => BoolPref('notif_desktop', true));

final notifSoundProvider =
    StateNotifierProvider<BoolPref, bool>((ref) => BoolPref('notif_sound', true));

final notifPreviewProvider =
    StateNotifierProvider<BoolPref, bool>((ref) => BoolPref('notif_preview', true));

final notifMentionOnlyDmProvider =
    StateNotifierProvider<BoolPref, bool>((ref) => BoolPref('notif_mention_dm', false));

// ── Privacy preferences ──────────────────────────────────────────────────────

final privacyPresenceProvider =
    StateNotifierProvider<BoolPref, bool>((ref) => BoolPref('privacy_presence', true));

final privacyReadReceiptsProvider =
    StateNotifierProvider<BoolPref, bool>((ref) => BoolPref('privacy_read_receipts', true));

final privacyTypingProvider =
    StateNotifierProvider<BoolPref, bool>((ref) => BoolPref('privacy_typing', true));

// ── Theme persistence helpers ────────────────────────────────────────────────

Future<void> saveThemePrefs({
  bool? isDark,
  int? accentIdx,
  double? radius,
  double? motion,
}) async {
  final p = await SharedPreferences.getInstance();
  if (isDark != null) await p.setBool('theme_dark', isDark);
  if (accentIdx != null) await p.setInt('theme_accent', accentIdx);
  if (radius != null) await p.setDouble('theme_radius', radius);
  if (motion != null) await p.setDouble('theme_motion', motion);
}

Future<({bool isDark, int accentIdx, double radius, double motion})>
    loadThemePrefs() async {
  final p = await SharedPreferences.getInstance();
  return (
    isDark: p.getBool('theme_dark') ?? true,
    accentIdx: p.getInt('theme_accent') ?? 0,
    radius: p.getDouble('theme_radius') ?? 12.0,
    motion: p.getDouble('theme_motion') ?? 1.0,
  );
}

// ── Server banner persistence ─────────────────────────────────────────────────
// Stored as a single JSON map under 'server_banners': homeserverUrl → mxcUri

const _kServerBannersKey = 'server_banners';

Future<Map<String, String>> loadAllServerBanners() async {
  final p = await SharedPreferences.getInstance();
  final raw = p.getString(_kServerBannersKey);
  if (raw == null) return {};
  try {
    final decoded = jsonDecode(raw) as Map<String, dynamic>;
    return decoded.map((k, v) => MapEntry(k, v as String));
  } catch (_) {
    return {};
  }
}

Future<void> saveServerBanner(String homeserverUrl, String? mxcUri) async {
  final p = await SharedPreferences.getInstance();
  final current = await loadAllServerBanners();
  if (mxcUri == null || mxcUri.isEmpty) {
    current.remove(homeserverUrl);
  } else {
    current[homeserverUrl] = mxcUri;
  }
  await p.setString(_kServerBannersKey, jsonEncode(current));
}
