import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hub/shared/utils/cache_util.dart';
import 'package:hub/shared/utils/storage_util.dart';

class SecureStorageHelper extends ChangeNotifier implements Storage {
  static final SecureStorageHelper _instance = SecureStorageHelper._internal();
  final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();

  factory SecureStorageHelper() => _instance;

  SecureStorageHelper._internal();

  static SecureStorageHelper get instance => _instance;

  Future<void> setAndCacheString(
      String key, String value, Function(String) cacheSetter) async {
    log('SecureStorageHelper -> setAndCacheString value for key: $key to $value');
    await _secureStorage.write(key: key, value: value);
    CacheUtil.instance.set(key, value);
    cacheSetter(value);
  }

  Future<void> setAndCacheBool(
      String key, bool value, Function(bool) cacheSetter) async {
    log('SecureStorageHelper -> setAndCacheBool value for key: $key to $value');
    await _secureStorage.write(key: key, value: value.toString());
    CacheUtil.instance.set(key, value);
    cacheSetter(value);
  }

  Future<void> setAndCacheObject(
      String key, String value, Function(String) cacheSetter) async {
    log('SecureStorageHelper -> setAndCacheObject value for key: $key to $value');
    await _secureStorage.write(key: key, value: value);
    CacheUtil.instance.set(key, value);
    cacheSetter(value);
  }

  Future<String?> getString(String key) async {
    var value = CacheUtil.instance.get(key);
    if (value == null) {
      value = await _secureStorage.read(key: key);
      CacheUtil.instance.set(key, value);
    }
    log('SecureStorageHelper -> getString $value for key: $key');
    return value;
  }

  Future<bool?> getBool(String key) async {
    var value = CacheUtil.instance.get(key);
    if (value == null || value == 'null') {
      value = await _secureStorage.read(key: key);
      CacheUtil.instance.set(key, value);
      log('SecureStorageHelper -> getBool $value for key: $key');
      return value == 'true';
    }
    log('SecureStorageHelper -> getBool $value for key: $key');
    return value == 'true' || value == true;
  }

  Future<BuildContext?> getObject(String key) async {
    var value = CacheUtil.instance.get(key);
    if (value == null) {
      value = await _secureStorage.read(key: key);
      CacheUtil.instance.set(key, value);
    }
    log('SecureStorageHelper -> getObject $value for key: $key');
    return value as BuildContext?;
  }

  @override
  Future<void> set(
      String key, dynamic value, Function(dynamic) cacheSetter) async {
    if (value is String? || value is String) {
      await setAndCacheString(key, value!, cacheSetter);
    } else if (value is bool? || value is bool) {
      await setAndCacheBool(key, value, cacheSetter);
    } else if (value is BuildContext || value is BuildContext?) {
      await setAndCacheObject(key, value.toString(), cacheSetter);
    }
  }

  @override
  Future<dynamic> get(String key) async {
    log('SecureStorageHelper -> get value for key: $key');
    var stringValue = await getString(key);
    if (stringValue != null) return stringValue;

    var boolValue = await getBool(key);
    if (boolValue != null) return boolValue;

    var objectValue = await getObject(key);
    if (objectValue != null) return objectValue;

    return null;
  }

  @override
  Future<void> delete(String key) async {
    log('SecureStorageHelper -> delete value for key: $key');
    await _secureStorage.delete(key: key);
    CacheUtil.instance.delete(key);
  }

  Future<void> purge() async {
    log('SecureStorageHelper -> Purging secure storage');
    await _secureStorage.deleteAll();

    CacheUtil.instance.clear();
  }
}
