import 'dart:developer';
import 'dart:ffi';

import 'package:flutter/material.dart';
import 'package:hub/shared/helpers/secure_storage_helper.dart';
import 'package:hub/shared/helpers/shared_preferences_storage_helper.dart';
import 'package:hub/shared/helpers/sqlite_storage_helper.dart';
import 'package:hub/shared/utils/cache_util.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/log_util.dart';
import 'package:shared_preferences/shared_preferences.dart';

enum StorageType { secureStorage, sharedPreferences, dbSQLite3 }

abstract class Storage {
  Future<void> set(String key, dynamic value, Function(dynamic) cacheSetter);
  Future<dynamic> get(String key);
  Future<void> delete(String key);
  Future<void> purge();
}

class StorageData {
  final String key;
  final dynamic value;
  final StorageType type;
  StorageData(this.key, this.value, this.type);
}

class StorageUtil {
  static final StorageUtil _instance = StorageUtil._internal();

  factory StorageUtil() {
    return _instance;
  }

  StorageUtil._internal();

  late final SQLiteStorageHelper _sqliteStorage;
  late final SecureStorageHelper _secureStorage;
  late final SharedPreferencesStorageHelper _sharedPreferences;
  bool _initialized = true;

  static Future<void> set(StorageData data) async {
    try {
      var currentValue = CacheUtil().get(data.key);
      if (currentValue != null && currentValue == data.value) {
        log('Value for key ${data.key} is already set to ${data.value}, skipping update.');
        return;
      }

      switch (data.type) {
        case StorageType.secureStorage:
          await SecureStorageHelper().set(data.key, data.value, (v) {});
          break;
        case StorageType.sharedPreferences:
          await SharedPreferencesStorageHelper()
              .set(data.key, data.value, (v) {});
          break;
        case StorageType.dbSQLite3:
          await SQLiteStorageHelper().set(data.key, data.value, (v) {});
          break;
      }
      CacheUtil().set(data.key, data.value);
    } catch (e) {
      log('Error setting data: $e');
    }
  }

  static Future<dynamic> get(StorageData data) async {
    try {
      var value = CacheUtil().get(data.key);
      if (value == null) {
        switch (data.type) {
          case StorageType.secureStorage:
            value = await SecureStorageHelper().get(data.key);
            break;
          case StorageType.sharedPreferences:
            value = await SharedPreferencesStorageHelper().get(data.key);
            break;
          case StorageType.dbSQLite3:
            value = await SQLiteStorageHelper().get(data.key);
            break;
        }
        CacheUtil().set(data.key, value);
      }
      return value;
    } catch (e) {
      log('Error getting data: $e');
      return null;
    }
  }

  static Future<void> delete(StorageData data) async {
    try {
      CacheUtil().delete(data.key);
      switch (data.type) {
        case StorageType.secureStorage:
          await SecureStorageHelper().delete(data.key);
          break;
        case StorageType.sharedPreferences:
          await SharedPreferencesStorageHelper().delete(data.key);
          break;
        case StorageType.dbSQLite3:
          await SQLiteStorageHelper().delete(data.key);
          break;
      }
    } catch (e) {
      log('Error deleting data: $e');
    }
  }

  static Future<void> purge() async {
    try {
      await SecureStorageHelper().purge();
      await SQLiteStorageHelper().purge();
      // await SharedPreferencesStorageHelper().purge();
    } catch (e) {
      log('Error purging data: $e');
    }
  }

  Future<bool> ensureInitialization() async {
    try {
      log('StorageUtil: Starting initialization');
      if(!_initialized) return true;
      await initSharedPreferences();
      await initSecureStorage();
      await initSQLiteStorage();
      if(_initialized) _initialized = false;
      if(_initialized) return true;
      return false;
    } catch (e, s) {
      log('Error initializing storage: $e');
      LogUtil.requestAPIFailed('$UniqueKey', '$UniqueKey', 'StorageUtil', e, s);
      return false;
    }
  }

  Future<void> initSharedPreferences() async {
    try {
      if(_initialized) _sharedPreferences = SharedPreferencesStorageHelper();
      _sharedPreferences.prefs ??= await SharedPreferences.getInstance();
      final bool milestone =
          _sharedPreferences.prefs?.getBool('fre_isFirstRun') ?? true;
      if (milestone) {
        isFirstRun = false;
        await _sharedPreferences.prefs?.setBool('fre_isFirstRun', false);
        isLogged = false;
        final String message = '';

        // _secureStorage.purge();
        // _sqliteStorage.purge();
      }
    } catch (e, s) {
      log('SharedPreferencesStorageHelper: Error during initialization');
      LogUtil.requestAPIFailed(
          '$UniqueKey', '$UniqueKey', 'SharedPreferencesStorageHelper', e, s);
    }
  }

  Future<void> initSecureStorage() async {
    log('SecureStorageHelper: Starting initialization');
    try {
      if(_initialized) _secureStorage = SecureStorageHelper();
      _email = await _secureStorage.getString('fre_email');
      _passwd = await _secureStorage.getString('fre_passwd');
      _deviceType = await _secureStorage.getString('fre_deviceType');
      _isLogged = await _secureStorage.getBool('fre_isLogged') ?? false;
      _tokenAPNS = await _secureStorage.getString('fre_tokenAPNS');
      _accessPass = await _secureStorage.getString('fre_accessPass');
      _panicPass = await _secureStorage.getString('fre_panicPass');
      _fingerprintPass = await _secureStorage.getString('fre_fingerprintPass');
      _haveLocal = await _secureStorage.getBool('fre_have_local') ?? false;
      _deviceDescription =
          await _secureStorage.getString('fre_deviceDescription');
    } catch (e, s) {
      log('SecureStorageHelper: Error during initialization: $e');
      LogUtil.requestAPIFailed(
          '$UniqueKey', '$UniqueKey', 'SecureStorageHelper', e, s);
    }
    log('SecureStorageHelper: Initialization complete');
  }

  Future<void> initSQLiteStorage() async {
    log('SQLiteStorageHelper: Starting initialization');
    try {
      if(_initialized) _sqliteStorage = SQLiteStorageHelper();
      await _sqliteStorage.database;
      _devUUID = await _sqliteStorage.get('fre_devUUID') ?? '';
      _userUUID = await _sqliteStorage.get('fre_userUUID') ?? '';
      _userDevUUID = await _sqliteStorage.get('fre_userDevUUID') ?? '';
      _status = await _sqliteStorage.get('fre_status') ?? '';
      _userName = await _sqliteStorage.get('fre_userName') ?? '';
      _cliUUID = await _sqliteStorage.get('fre_cliUUID') ?? '';
      _ownerUUID = await _sqliteStorage.get('fre_ownerUUID') ?? '';
      _cliName = await _sqliteStorage.get('fre_cliName') ?? '';
      _petAmountRegister = await _sqliteStorage.get('fre_petAmountRegister') ?? '';
      _whatsapp = await _sqliteStorage.getBoolean('fre_whatsapp');
      _provisional = await _sqliteStorage.getBoolean('fre_provisional');
      _pets = await _sqliteStorage.getBoolean('fre_pets');
      _local = await _sqliteStorage.getBoolean('fre_local');
      _notify = await _sqliteStorage.getBoolean('fre_notify');
      _fingerprint = await _sqliteStorage.getBoolean('fre_fingerprint');
      _access = await _sqliteStorage.getBoolean('fre_access');
      _panic = await _sqliteStorage.getBoolean('fre_panic');
      _person = await _sqliteStorage.getBoolean('fre_person');
      _requestOSnotification =
          await _sqliteStorage.getBoolean('fre_requestOSnotification');
    } catch (e, s) {
      log('SQLiteStorageHelper: Error during initialization: $e');
      LogUtil.requestAPIFailed(
          '$UniqueKey', '$UniqueKey', 'SQLiteStorageHelper', e, s);
    }
    log('SQLiteStorageHelper: Initialization complete');
  }

  bool _isRecovered = false;
  bool get isRecovered => _isRecovered;
  set isRecovered(bool value) => _isRecovered = value;

  bool _isFirstRun = true;
  bool get isFirstRun => _isFirstRun;
  set isFirstRun(bool value) {
    _isFirstRun = value;
    _sharedPreferences.set('fre_isFirstRun', value, (v) => _isFirstRun = v);
  }

  String? _deviceDescription;
  String get deviceDescription => _deviceDescription ?? '';
  set deviceDescription(String value) {
    _deviceDescription = value;
    _secureStorage.set('fre_deviceDescription', value, (v) => _deviceDescription = v);
  }

  BuildContext? _context;
  BuildContext? get context => _context;
  set context(BuildContext? value) {
    _context = value;
    _secureStorage.set('fre_context', value.toString(), (v) => _context = value);
  }

  bool _haveLocal = false;
  bool get haveLocal => _haveLocal;
  set haveLocal(bool value) {
    _haveLocal = value;
    _secureStorage.set('fre_have_local', value ?? false, (v) => _haveLocal = value);
  }

  String? _fingerprintPass;
  String get fingerprintPass => _fingerprintPass ?? '';
  set fingerprintPass(String value) {
    _fingerprintPass = value;
    _secureStorage.set('fre_fingerprintPass', value, (v) => _fingerprintPass = v);
  }

  String? _accessPass;
  String get accessPass => _accessPass ?? '';
  set accessPass(String value) {
    _accessPass = value;
    _secureStorage.set('fre_accessPass', value, (v) => _accessPass = v);
  }

  String? _panicPass;
  String get panicPass => _panicPass ?? '';
  set panicPass(String value) {
    _panicPass = value;
    _secureStorage.set('fre_panicPass', value, (v) => _panicPass = v);
  }

  String? _tokenAPNS;
  String? get tokenAPNS => _tokenAPNS;
  set tokenAPNS(String? value) {
    _tokenAPNS = value;
    _secureStorage.set('fre_tokenAPNS', value ?? '', (v) => _tokenAPNS = v);
  }

  String? _email;
  String get email => _email ?? '';
  set email(String value) {
    _email = value;
    _secureStorage.set('fre_email', value, (v) => _email = v);
  }

  String? _passwd;
  String get passwd => _passwd ?? '';
  set passwd(String value) {
    _passwd = value;
    _secureStorage.set('fre_passwd', value, (v) => _passwd = v);
  }

  String? _deviceType;
  String get deviceType => _deviceType ?? '';
  set deviceType(String value) {
    _deviceType = value;
    _secureStorage.set('fre_deviceType', value, (v) => _deviceType = v);
  }

  bool _isLogged = false;
  bool get isLogged => _isLogged;
  set isLogged(bool value) {
    _isLogged = value;
    _secureStorage.set('fre_isLogged', value, (v) => _isLogged = v);
  }

  String? _token;
  String get token => _token ?? '';
  set token(String value) {
    _token = value;
    _secureStorage.set('fre_token', value, (v) => _token = v);
  }

  String _devUUID = '';
  String get devUUID => _devUUID;
  set devUUID(String value) {
    _devUUID = value;
    _sqliteStorage.set('fre_devUUID', value, (v) {});
  }

  String _userUUID = '';
  String get userUUID => _userUUID;
  set userUUID(String value) {
    _userUUID = value;
    _sqliteStorage.set('fre_userUUID', value, (v) {});
  }

  String _userDevUUID = '';
  String get userDevUUID => _userDevUUID;
  set userDevUUID(String value) {
    _userDevUUID = value;
    _sqliteStorage.set('fre_userDevUUID', value, (v) {});
  }

  String _status = '';
  String get status => _status;
  set status(String value) {
    _status = value;
    _sqliteStorage.set('fre_status', value, (v) {});
  }

  String _userName = '';
  String get userName => _userName;
  set userName(String value) {
    _userName = value;
    _sqliteStorage.set('fre_userName', value, (v) {});
  }

  String _cliUUID = '';
  String get cliUUID => _cliUUID;
  set cliUUID(String value) {
    _cliUUID = value;
    _sqliteStorage.set('fre_cliUUID', value, (v) {});
  }

  String _ownerUUID = '';
  String get ownerUUID => _ownerUUID;
  set ownerUUID(String value) {
    _ownerUUID = value;
    _sqliteStorage.set('fre_ownerUUID', value, (v) {});
  }

  String _cliName = '';
  String get cliName => _cliName;
  set cliName(String value) {
    _cliName = value;
    _sqliteStorage.set('fre_cliName', value, (v) {});
  }

  String _petAmountRegister = '';
  String get petAmountRegister => _petAmountRegister;
  set petAmountRegister(String value) {
    _petAmountRegister = value;
    _sqliteStorage.set('fre_petAmountRegister', value, (v) {});
  }

  bool _whatsapp = false;
  bool get whatsapp => _whatsapp;
  set whatsapp(bool value) {
    _whatsapp = value;
    _sqliteStorage.set('fre_whatsapp', value, (v) {});
  }

  bool _provisional = false;
  bool get provisional => _provisional;
  set provisional(bool value) {
    _provisional = value;
    _sqliteStorage.set('fre_provisional', value, (v) {});
  }

  bool _pets = false;
  bool get pets => _pets;
  set pets(bool value) {
    _pets = value;
    _sqliteStorage.set('fre_pets', value, (v) {});
  }

  bool _local = false;
  bool get local => _local;
  set local(bool value) {
    _local = value;
    _sqliteStorage.set('fre_local', value, (v) {});
  }

  bool _notify = false;
  bool get notify => _notify;
  set notify(bool value) {
    _notify = value;
    _sqliteStorage.set('fre_notify', value, (v) {});
  }

  bool _fingerprint = false;
  bool get fingerprint => _fingerprint;
  set fingerprint(bool value) {
    _fingerprint = value;
    _sqliteStorage.set('fre_fingerprint', value, (v) {});
  }

  bool _access = false;
  bool get access => _access;
  set access(bool value) {
    _access = value;
    _sqliteStorage.set('fre_access', value, (v) {});
  }

  bool _panic = false;
  bool get panic => _panic;
  set panic(bool value) {
    _panic = value;
    _sqliteStorage.set('fre_panic', value, (v) {});
  }

  bool _person = false;
  bool get person => _person;
  set person(bool value) {
    _person = value;
    _sqliteStorage.set('fre_person', value, (v) {});
  }

  bool _requestOSnotification = false;
  bool get requestOSnotification => _requestOSnotification;
  set requestOSnotification(bool value) {
    _requestOSnotification = value;
    _sqliteStorage.set('fre_requestOSnotification', value, (v) {});
  }

  String get createdAt => '0000-00-00 00:00:00';
}
