import 'package:hub/shared/utils/cache_util.dart'; import 'package:hub/shared/utils/storage_util.dart'; import 'package:sqflite/sqflite.dart'; import 'dart:developer'; import 'package:path/path.dart'; class DatabaseConfig { static const String dbName = 'database.db'; static const int dbVersion = 1; static const String tableKeychain = 'keychain'; static const String columnKey = 'key'; static const String columnValue = 'value'; static const String columnType = 'type'; static const String columnUpdateAt = 'updateAt'; static const String columnResolvedAt = 'resolvedAt'; static const String columnCreatedAt = 'createdAt'; static const List> initialData = [ {'key': 'devUUID', 'value': '', 'type': 'user'}, {'key': 'userUUID', 'value': '', 'type': 'user'}, {'key': 'userDevUUID', 'value': '', 'type': 'user'}, {'key': 'status', 'value': '', 'type': 'user'}, {'key': 'userName', 'value': '', 'type': 'user'}, {'key': 'cliUUID', 'value': '', 'type': 'local'}, {'key': 'ownerUUID', 'value': '', 'type': 'local'}, {'key': 'cliName', 'value': '', 'type': 'local'}, {'key': 'whatsapp', 'value': 'false', 'type': 'util'}, {'key': 'provisional', 'value': 'false', 'type': 'util'}, {'key': 'pets', 'value': 'false', 'type': 'util'}, {'key': 'local', 'value': 'false', 'type': 'util'}, {'key': 'notify', 'value': 'false', 'type': 'util'}, {'key': 'fingerprint', 'value': 'false', 'type': 'util'}, {'key': 'access', 'value': 'false', 'type': 'util'}, {'key': 'panic', 'value': 'false', 'type': 'util'}, {'key': 'person', 'value': 'false', 'type': 'util'}, {'key': 'requestOSnotification', 'value': 'false', 'type': 'util'}, {'key': 'petAmountRegister', 'value': '', 'type': 'local'}, ]; } class SQLiteStorageHelper implements Storage { static final SQLiteStorageHelper _instance = SQLiteStorageHelper._internal(); static Database? _database; static String? _databasePath; factory SQLiteStorageHelper() => _instance; SQLiteStorageHelper._internal(); static SQLiteStorageHelper get instance => _instance; Future get database async { log('Getting database instance'); if (_database != null) return _database!; _database = await _initDatabase(); return _database!; } Future _getDatabasePath() async { log('Getting database path'); if (_databasePath != null) return _databasePath!; final databasesPath = await getDatabasesPath(); _databasePath = join(databasesPath, DatabaseConfig.dbName); log('Database path: $_databasePath'); return _databasePath!; } Future _initDatabase() async { log('Initializing database'); final path = await _getDatabasePath(); return await openDatabase( path, version: DatabaseConfig.dbVersion, onCreate: _onCreate, onOpen: _onOpen, onUpgrade: _onUpgrade, onDowngrade: _onDowngrade, onConfigure: _onConfigure, ).catchError((error) { log('Error initializing database: $error'); throw error; }).whenComplete(() async { log('Database initialization complete'); await setupLocalVariables(); }); } Future _onCreate(Database db, int version) async { log('Creating tables...'); await db.execute(''' CREATE TABLE ${DatabaseConfig.tableKeychain} ( ${DatabaseConfig.columnKey} TEXT UNIQUE, ${DatabaseConfig.columnValue} TEXT, ${DatabaseConfig.columnType} TEXT, ${DatabaseConfig.columnUpdateAt} TEXT, ${DatabaseConfig.columnResolvedAt} TEXT, ${DatabaseConfig.columnCreatedAt} TEXT ); '''); await _insertInitialData(db); log('Tables created'); } Future _insertInitialData(Database db) async { log('Inserting initial data'); final batch = db.batch(); for (var data in DatabaseConfig.initialData) { batch.insert(DatabaseConfig.tableKeychain, data); } await batch.commit(noResult: true); log('Initial data inserted'); } Future _onOpen(Database db) async { log('Opening database'); await _checkExistingData(db); } Future _onUpgrade(Database db, int oldVersion, int newVersion) async { log('Upgrading database from version $oldVersion to $newVersion'); } Future _onDowngrade(Database db, int oldVersion, int newVersion) async { log('Downgrading database from version $oldVersion to $newVersion'); } Future _onConfigure(Database db) async { log('Configuring database'); } Future _checkExistingData(Database db) async { log('Checking existing data'); try { final maps = await db.query(DatabaseConfig.tableKeychain); log('Existing data: $maps'); } catch (error) { log('Error checking existing data: $error'); } } Future setupLocalVariables() async { log('Setting up local variables'); try { await _database?.transaction((txn) async { final keys = [ 'devUUID', 'userUUID', 'userDevUUID', 'status', 'userName', 'cliUUID', 'ownerUUID', 'cliName', 'petAmountRegister', 'whatsapp', 'provisional', 'pets', 'local', 'notify', 'fingerprint', 'access', 'panic', 'person', 'requestOSnotification' ]; for (var key in keys) { log('Fetching value for key: $key'); final result = await txn.query( DatabaseConfig.tableKeychain, where: '${DatabaseConfig.columnKey} = ?', whereArgs: [key], ); log('Result for key $key: $result'); } }); log('Local variables setup complete'); } catch (error) { log('Error setting up local variables: $error'); } } Future getBoolean(String key) async { log('Getting boolean value for key: $key'); final value = await get(key); return value == 'true'; } @override Future get(String key) async { log('Getting value for key: $key'); final cachedValue = CacheUtil().get(key); if (cachedValue != null) { log('Found cached value for key: $key'); return cachedValue; } try { final db = await database; final result = await db.query( DatabaseConfig.tableKeychain, columns: [DatabaseConfig.columnValue], where: '${DatabaseConfig.columnKey} = ?', whereArgs: [key], ); if (result.isNotEmpty) { final value = result.first[DatabaseConfig.columnValue]; CacheUtil().set(key, value); log('Value for key $key: $value'); return value; } log('No value found for key: $key'); return null; } catch (error) { log('Error getting value for key $key: $error'); return null; } } @override Future set(String key, dynamic value, Function(dynamic) cacheSetter) async { log('Setting value for key: $key to $value'); CacheUtil().set(key, value); final db = await database; final data = { DatabaseConfig.columnKey: key, DatabaseConfig.columnValue: value.toString(), DatabaseConfig.columnUpdateAt: DateTime.now().toIso8601String(), DatabaseConfig.columnCreatedAt: DateTime.now().toIso8601String(), }; final result = await db.insert( DatabaseConfig.tableKeychain, data, conflictAlgorithm: ConflictAlgorithm.replace, ); log('Value $value set for key: $key'); return result; } @override Future delete(String key) async { log('Deleting value for key: $key'); final db = await database; final result = await db.transaction((txn) async { return await txn.delete( DatabaseConfig.tableKeychain, where: '${DatabaseConfig.columnKey} = ?', whereArgs: [key], ); }); log('Value deleted for key: $key'); return result; } @override Future purge() async { log('Purging database'); await deleteDatabaseDB(); await database; log('Database purged'); } Future deleteDatabaseDB() async { log('Deleting database'); final path = await _getDatabasePath(); await deleteDatabase(path); log('Database deleted'); _database = null; } } class SqliteStorageDelegate {}