import 'dart:convert';

import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

import 'package:together_mobile/database/box_type.dart';
import 'package:together_mobile/models/init_get_it.dart';
import 'package:together_mobile/models/user_model.dart';
import 'package:together_mobile/utils/app_dir.dart';

class HiveDatabase {
  static bool _isInitialised = false;

  static Future<void> init() async {
    if (_isInitialised) {
      return;
    }

    List<int> encryptionKeyUint8List = await _getEncryptKey();

    await Hive.initFlutter(await getBoxDir());

    Box<ChatSetting> chatSettingBox =
        await Hive.openBox<ChatSetting>('chat_setting');

    final openedChats =
        chatSettingBox.values.where((element) => element.isOpen);

    for (var chatBox in openedChats) {
      await Hive.openBox<MessageT>(
        'message_${chatBox.contactId}',
        encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
        compactionStrategy: (entries, deletedEntries) => entries > 200,
      );
    }

    _isInitialised = true;
  }

  static void registerAdapter() {
    Hive.registerAdapter(ChatSettingAdapter());
    Hive.registerAdapter(MessageTAdapter());
  }

  static Future<Box<MessageT>> openMessageBox(String contactId) async {
    final encryptionKeyUint8List = await _getEncryptKey();
    late Box<MessageT> messageTBox;
    try {
      messageTBox = Hive.box<MessageT>('message_$contactId');
    } catch (e) {
      messageTBox = await Hive.openBox<MessageT>(
        'message_$contactId',
        encryptionCipher: HiveAesCipher(encryptionKeyUint8List),
        compactionStrategy: (entries, deletedEntries) => entries > 200,
      );
    }
    return messageTBox;
  }

  static Future<List<int>> _getEncryptKey() async {
    final id = getIt.get<UserAccount>().id;
    const secureStorage = FlutterSecureStorage();
    final encryptionKeyString = await secureStorage.read(key: 'encryptKey:$id');
    if (encryptionKeyString == null) {
      final key = Hive.generateSecureKey();
      await secureStorage.write(
        key: 'encryptKey:$id',
        value: base64Encode(key),
      );
    }
    String? key = await secureStorage.read(key: 'encryptKey:$id');
    final encryptionKeyUint8List = base64Url.decode(key!);

    return encryptionKeyUint8List;
  }

  static Future<void> close() async {
    _isInitialised = false;
    await Hive.close();
  }
}