import 'dart:convert' show jsonDecode, jsonEncode; import 'package:shared_preferences/shared_preferences.dart'; import '../model/bookmark.dart'; import '../model/collection.dart'; import '../model/settings.dart'; import 'json_file_service.dart'; class Storage { static const String _bookmarksKey = 'bookmarks'; static const String _collectionsKey = 'collections'; static SharedPreferencesWithCache? _prefsWithCache; static const String _settingsKey = 'settings'; static const String _statsKey = 'stats'; static Settings _currentSettings = Settings.defaults(); static Future initialize() async { _prefsWithCache = await SharedPreferencesWithCache.create( cacheOptions: const SharedPreferencesWithCacheOptions( allowList: { _collectionsKey, _bookmarksKey, _statsKey, _settingsKey, }, ), ); } static Settings loadSettings() { final jsonString = _prefs.getString(_settingsKey); if (jsonString != null) { final json = jsonDecode(jsonString) as Map; _currentSettings = Settings.fromJson(json); return _currentSettings; } else { final settings = Settings.defaults(); saveSettings(settings); return settings; } } static Future saveSettings(Settings settings) { final json = jsonEncode(settings.toJson()); _currentSettings = settings; return _prefs.setString(_settingsKey, json); } static List loadCollections() { final jsonString = _prefs.getString(_collectionsKey) ?? '[]'; final jsonList = jsonDecode(jsonString) as List; return jsonList .map((json) => Collection.fromJson(json as Map)) .toList(); } static List loadBookmarks() { final jsonString = _prefs.getString(_bookmarksKey) ?? '[]'; final jsonList = jsonDecode(jsonString) as List; return jsonList .map((json) => Bookmark.fromJson(json as Map)) .toList(); } static Future saveCollections(List collections) async { final jsonList = collections.map((c) => c.toJson()).toList(); await _prefs.setString(_collectionsKey, jsonEncode(jsonList)); if (_currentSettings.alwaysExportEnabled) saveDataToFile(); } static Future saveBookmarks(List bookmarks) async { final jsonList = bookmarks.map((b) => b.toJson()).toList(); await _prefs.setString(_bookmarksKey, jsonEncode(jsonList)); if (_currentSettings.alwaysExportEnabled) saveDataToFile(); } static List loadBookmarksForCollection(int collectionId) { final allBookmarks = loadBookmarks(); return allBookmarks.where((b) => b.collectionId == collectionId).toList(); } static Map loadPerCollectionBookmarkCount() { return loadBookmarks().fold({}, (map, bookmark) { map[bookmark.collectionId] ??= 0; map[bookmark.collectionId] = map[bookmark.collectionId]! + 1; return map; }); } static Future addBookmark(Bookmark bookmark) async { final bookmarks = loadBookmarks(); bookmarks.add(bookmark); await saveBookmarks(bookmarks); } static Future addOrUpdateBookmark(Bookmark bookmark) async { final bookmarks = loadBookmarks(); final index = bookmarks.indexWhere((b) => b.id == bookmark.id); if (index == -1) { bookmarks.add(bookmark); } else if (index >= 0) { bookmarks[index] = bookmark; } await saveBookmarks(bookmarks); } static Future addOrUpdateCollection(Collection collection) async { final collections = loadCollections(); final index = collections.indexWhere((b) => b.id == collection.id); if (index == -1) { collections.add(collection); } else if (index >= 0) { collections[index] = collection; } await saveCollections(collections); } static Future updateBookmarkById( int bookmarkId, { String? name, String? description, String? link, }) async { final bookmarks = loadBookmarks(); final index = bookmarks.indexWhere((b) => b.id == bookmarkId); if (index == -1) return; if (name != null) bookmarks[index].name = name; if (description != null) bookmarks[index].description = description; if (link != null) bookmarks[index].link = link; await saveBookmarks(bookmarks); } static Future deleteBookmark(Bookmark bookmark) async { final bookmarks = loadBookmarks(); bookmarks.remove(bookmark); await saveBookmarks(bookmarks); } static Future deleteBookmarkById(int bookmarkId) async { final bookmarks = loadBookmarks(); bookmarks.removeWhere((b) => b.id == bookmarkId); await saveBookmarks(bookmarks); } static Future deleteBookmarksForCollection(int collectionId) async { final bookmarks = loadBookmarks(); bookmarks.removeWhere((b) => b.collectionId == collectionId); await saveBookmarks(bookmarks); } static Future deleteCollection(Collection collection) async { final collections = loadCollections(); final bookmarks = loadBookmarks(); bookmarks.removeWhere((bookmark) => bookmark.collectionId == collection.id); collections.remove(collection); await saveBookmarks(bookmarks); await saveCollections(collections); } static Map getStats() { final statsJson = _prefs.getString(_statsKey) ?? '{}'; final stats = jsonDecode(statsJson) as Map; return { 'totalCollections': stats['totalCollections'] ?? 0, 'totalBookmarks': stats['totalBookmarks'] ?? 0, }; } static Future updateStats() async { final collections = loadCollections(); final bookmarks = loadBookmarks(); final stats = { 'totalCollections': collections.length, 'totalBookmarks': bookmarks.length, 'lastUpdated': DateTime.now().millisecondsSinceEpoch, }; await _prefs.setString(_statsKey, jsonEncode(stats)); } static Future exportToJsonFile() => JsonFileService.exportToJson( collections: loadCollections(), bookmarks: loadBookmarks(), ); static Future importFromJsonFile() async { final import = await JsonFileService.importFromJson(); if (import.bookmarks.isNotEmpty || import.collections.isNotEmpty) { saveBookmarks(import.bookmarks); saveCollections(import.collections); return true; } return false; } static Future selectDirectoryPath() => JsonFileService.selectDirectoryPath(); static Future saveDataToFile() => JsonFileService.saveDataToFile( loadCollections(), loadBookmarks(), _currentSettings.exportDirectoryPath, ); static SharedPreferencesWithCache get _prefs { if (_prefsWithCache == null) { throw StateError( 'BookmarkStorage not initialized. Call initialize() first.', ); } return _prefsWithCache!; } }