import 'dart:io';

import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';

import 'package:hive_flutter/hive_flutter.dart';

class Preferences {
  static const _preferencesBox = '_preferencesBox';

  static const String _appLanguageKey = 'app_language_key';
  static const String _addressKey = 'address_key';
  static const String _landmarkKey = 'landmark_key';
  static const String _userPhoneNumber = 'user_phone_number';
  static const String _userFirstName = 'user_first_name';
  static const String _userLastName = 'user_last_name';
  static const String _userTokenKey = 'user_token_key';
  static const String _userTokenKeyForDirectus = 'user_token_key_for_directus';
  static const String _userRefreshTokenKey = 'user_refresh_token_key';
  static const String _userRefreshTokenKeyForDirectus =
      'user_refresh_token_key_for_directus';
  static const String _userMessagingToken = 'user_firebase_token';
  static const String _hasUserFullName = 'has_user_full_name';
  static const String _imagePath = 'user_image_path';
  static const String _emailKey = 'email_key';
  static const String _genderKey = 'gender_key';
  static const String _birthDateKey = 'birth_date_key';

  static const String _mapType = 'mapType';
  static const String _downloadPath = 'download_path';
  static const String _deviceModel = 'device_model';
  static const String _deviceId = 'device_id';
  static const String _roomId = 'room_id';
  static const String _isRoomSendedToServer = 'isRoomSendedToServer';
  static const String _isChatStarted = 'is_chat_started';
  static const String _lastVisit = 'last_visit';
  static const String _isRegisteredDevice = 'register_device';

  static const String _firstOpened = 'firstOpen';
  static const String _firstOpened2 = 'firstOpen2';
  static const String _chatToken = 'chatToken';
  // static const String _userLocation = 'userLocation';

  final Box<dynamic> _box;

  Preferences._(this._box);

  static Future<void> createHiveBox() async {
    Directory directory = await getApplicationDocumentsDirectory();

    await Hive.initFlutter(directory.path);

    getInstance();
  }

  static void closeHiveBox() {
    Hive.close();
  }

  static int index = 0;

  // This doesn't have to be a singleton.
  // We just want to make sure that the box is open, before we start getting/setting objects on it
  static Future<Preferences?>? getInstance() async {
    Box<dynamic>? box;
    try {
      await Hive.openBox<dynamic>(_preferencesBox);
      box = Hive.box<dynamic>(_preferencesBox);
      index = 0;
      return Preferences._(box);
    } catch (err) {
      /// box could not be opened.
      if (index == 20) {
        index = 0;
        return null;
      } else {
        index++;
        return getInstance();
      }
      // bool success = false;
      // int index = 0;
      // while (success == false) {
      //   var _boxName = _preferencesBox + index.toString();
      //   String? _err;
      //   try {
      //     box = await Hive.openBox(_boxName);
      //   } catch (err) {
      //     _err = err.toString();
      //   }
      //   if (_err == null) {
      //     print("Hive box opened with name " + _boxName);
      //     success = true;
      //     if (box != null) return Preferences._(box);
      //   } else if (index > 100) {
      //     throw ("Hive box could not be opened.");
      //   }
      //   index++;
      // }
    }
  }

  //helpers
  T _getValue<T>(dynamic key, {T? defaultValue}) =>
      _box.get(key, defaultValue: defaultValue) as T;

  Future<void> _setValue<T>(dynamic key, T value) => _box.put(key, value);

  //save token
  String? getToken() => _getValue(_userTokenKey, defaultValue: null);
  Future<void> setToken(String? token) => _setValue(_userTokenKey, token);

  //save App language
  String getAppLanguage() => _getValue(_appLanguageKey, defaultValue: "");
  Future<void> setAppLanguage(String appLanguageKey) =>
      _setValue(_appLanguageKey, appLanguageKey);

  //save address
  String getAddress() => _getValue(_addressKey, defaultValue: "");
  Future<void> setAddress(String addressKey) =>
      _setValue(_addressKey, addressKey);

  //save landmark
  String getLandmark() => _getValue(_landmarkKey, defaultValue: "");
  Future<void> setLandmark(String landmarkKey) =>
      _setValue(_landmarkKey, landmarkKey);

  //save phone number
  String getPhoneNumber() => _getValue(_userPhoneNumber, defaultValue: "");
  Future<void> setPhoneNUmber(String userPhoneNumber) =>
      _setValue(_userPhoneNumber, userPhoneNumber);

  //save first name
  String getFirstName() => _getValue(_userFirstName, defaultValue: "");
  Future<void> setFirstName(String userFirstName) =>
      _setValue(_userFirstName, userFirstName);

  //save last name
  String getLastName() => _getValue(_userLastName, defaultValue: "");
  Future<void> setLastName(String userLastName) =>
      _setValue(_userLastName, userLastName);

  //save user tokenKey for directus
  String getTokenKeyForDirectus() =>
      _getValue(_userTokenKeyForDirectus, defaultValue: "");
  Future<void> setTokenKeyForDirectus(String userTokenKeyForDirectus) =>
      _setValue(_userTokenKeyForDirectus, userTokenKeyForDirectus);

  //save userRefreshTokenKey
  String? getRefreshToken() =>
      _getValue(_userRefreshTokenKey, defaultValue: null);
  Future<void> setRefreshToken(String? userRefreshTokenKey) =>
      _setValue(_userRefreshTokenKey, userRefreshTokenKey);

  //save userRefreshTokenKeyForDirectus
  String getRefreshTokenForDirectus() =>
      _getValue(_userRefreshTokenKeyForDirectus, defaultValue: "");
  Future<void> setRefreshTokenForDirectus(
          String userRefreshTokenKeyForDirectus) =>
      _setValue(
          _userRefreshTokenKeyForDirectus, userRefreshTokenKeyForDirectus);

  //save messaging token
  String? getMessagingToken() =>
      _getValue(_userMessagingToken, defaultValue: null);
  Future<void> setMessagingToken(String? userMessagingToken) =>
      _setValue(_userMessagingToken, userMessagingToken);

  //save chat token
  String? getChatToken() => _getValue(_chatToken, defaultValue: null);
  Future<void> setChatToken(String? chatToken) =>
      _setValue(_chatToken, chatToken);
  //save hasUserFullName
  bool getHasUserFullName() => _getValue(_hasUserFullName, defaultValue: false);
  Future<void> setHasUserFullName(bool hasUserFullName) =>
      _setValue(_hasUserFullName, hasUserFullName);

  //save imagePath
  String getImagePath() => _getValue(_imagePath, defaultValue: "");
  Future<void> setImagePath(String imagePath) =>
      _setValue(_imagePath, imagePath);

  //save hasUserFullName
  String getEmail() => _getValue(_emailKey, defaultValue: "");
  Future<void> setEmail(String emailKey) => _setValue(_emailKey, emailKey);

  //save gender
  String getGender() => _getValue(_genderKey, defaultValue: "");
  Future<void> setGender(String genderKey) => _setValue(_genderKey, genderKey);

  //save hasUserFullName
  String getBirthDate() => _getValue(_birthDateKey, defaultValue: "");
  Future<void> setBirthDate(String birthDateKey) =>
      _setValue(_birthDateKey, birthDateKey);

  //save mapType
  String getMapType() => _getValue(_mapType, defaultValue: "");
  Future<void> setMapType(String mapType) => _setValue(_mapType, mapType);

  //save user first open
  bool getFirstOpen() => _getValue(_firstOpened, defaultValue: false);
  Future<void> setFirstOpen(bool firstOpened) =>
      _setValue(_firstOpened, firstOpened);

  //save user first open
  bool getFirstOpen2() => _getValue(_firstOpened2, defaultValue: false);
  Future<void> setFirstOpen2(bool firstOpened) =>
      _setValue(_firstOpened2, firstOpened);

  //save user download path
  String getDownloadPath() => _getValue(_downloadPath, defaultValue: "");
  Future<void> setDownloadPath(String downloadPath) =>
      _setValue(_downloadPath, downloadPath);

  //save user download path
  String? getDeviceModel() => _getValue(_deviceModel, defaultValue: null);
  Future<void> setDeviceModel(String? deviceModel) =>
      _setValue(_deviceModel, deviceModel);

  //save user download path
  String? getDeviceId() => _getValue(_deviceId, defaultValue: null);
  Future<void> setDeviceId(String? deviceId) => _setValue(_deviceId, deviceId);

  //save user download path
  String? getRoomId() => _getValue(_roomId, defaultValue: null);
  Future<void> setRoomId(String? roomId) => _setValue(_roomId, roomId);

  //save user download path
  bool isChatStarted() => _getValue(_isChatStarted, defaultValue: false);
  Future<void> setChatStarted(bool isChatStarted) =>
      _setValue(_isChatStarted, isChatStarted);

  String? getLastVisit() => _getValue(_lastVisit, defaultValue: null);
  Future<void> setLastVisit(String? lastVisit) =>
      _setValue(_lastVisit, lastVisit);

  bool isRegisteredDevice() =>
      _getValue(_isRegisteredDevice, defaultValue: false);

  Future<void> setRegisteredDevice(bool isRegisteredDevice) =>
      _setValue(_isRegisteredDevice, isRegisteredDevice);

  bool isRoomSended() => _getValue(_isRoomSendedToServer, defaultValue: false);
  Future<void> setRoomIsSended(bool isRoomSendedToServer) =>
      _setValue(_isRoomSendedToServer, isRoomSendedToServer);

  // int? getUserLocation() => _getValue(_userLocation, defaultValue: null);

  // Future<void> setUserLocation(int? location) =>
  //     _setValue(_userLocation, location);
}
