import 'package:comwell_key_app/services/api.dart';
import 'package:common/utils/env_utils.dart';
import 'package:comwell_key_app/utils/secure_storage.dart';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:seos_mobile_keys_plugin/app_usage_api.dart';
import 'package:seos_mobile_keys_plugin/seos_mobile_keys_plugin.dart';
import 'package:comwell_key_app/common/const.dart' as constants;

class SeosRepository {
  final SecureStorage _secureStorage;
  final Api _api;
  final SeosMobileKeysPlugin _seosMobileKeysPlugin;
  bool _pluginStarted = false;

  SeosRepository(this._secureStorage, this._api, this._seosMobileKeysPlugin);

  Future<void> startMobilePlugin() async {
    final mobileKeysOptions = {
      "MobileKeysOptionApplicationId": dotenv.MOBILE_KEYS_OPTION_APPLICATION_ID,
      "MobileKeysOptionAppDescription": dotenv.MOBILE_KEYS_OPTION_APP_DESCRIPTION,
      "MobileKeysOptionVersion": dotenv.MOBILE_KEYS_OPTION_VERSION,
      "MobileKeysOptionLockServiceCodes": [1],
      "MobileKeysOptionLogsMail": dotenv.MOBILE_KEYS_OPTION_LOGS_MAIL,
    };

    try {
      if (!_pluginStarted) {
        await _seosMobileKeysPlugin.startUp(mobileKeysOptions);
      }
    } on PlatformException catch (_) {
      // seosMobileKeysPlugin.startUp will throw an error if it's already been started,
      // which we can safely ignore
    } catch (e, st) {
      // Any other error, we log
      debugPrint("qqq startError=$e, $st");
    } finally {
      _pluginStarted = true;
    }
    try {
      final isEndpointSetup = await _seosMobileKeysPlugin.isEndpointSetup();
      if (isEndpointSetup) {
        await _updateEndpont();
      } else {
        final invitationCode = await _api.createEndpointRegistration();
        await _seosMobileKeysPlugin.setupEndpoint(invitationCode);

        await Future<void>.delayed(const Duration(seconds: 2));
        await _seosMobileKeysPlugin.updateEndpoint();
      }
    } on PlatformException catch (e) {
      throw Exception('Failed to init MobileKeysManager - ${e.toString()}');
    } catch (e) {
      throw Exception('Failed to init start: $e');
    }
  }

  Future<void> _updateEndpont() async {
    await _seosMobileKeysPlugin.updateEndpoint();
    final isEndpointSetupRecheck = await _seosMobileKeysPlugin.isEndpointSetup();
    // Required for AAH certification 3.3
    if (!isEndpointSetupRecheck) throw Exception("Endpoint is not set up");
  }

  Future<bool> isEndpointSetup({bool firstLaunch = true}) async {
    if (!_pluginStarted) return false;
    try {
      return _seosMobileKeysPlugin.isEndpointSetup();
    } catch (e) {
      throw Exception('Failed to check if endpoint setup - ${e.toString()}');
    }
  }

  Future<void> provisionKey({required String bookingId, required String hotelCode}) async {
    if (!_pluginStarted) return;

    try {
      await _api.provisionKey(bookingId, hotelCode);
      await _seosMobileKeysPlugin.updateEndpoint();
    } catch (e) {
      throw Exception('Failed to provision a key - ${e.toString()}');
    }
  }

  Future<List<MobileKeysKey>> refreshKeys() async {
    if (!_pluginStarted) return [];
    try {
      final List<MobileKeysKey> listOfKeys = await _seosMobileKeysPlugin.listMobileKeys();
      await _secureStorage.write(constants.hasKey, DateTime.now().toString());
      return listOfKeys;
    } catch (e) {
      throw Exception('Failed to list keys - ${e.toString()}');
    }
  }

  Future<void> terminateEndpoint() async {
    if (!_pluginStarted) return;
    try {
      await _seosMobileKeysPlugin.terminateEndpoint();
    } catch (e) {
      throw Exception('Failed to terminate endpoint - ${e.toString()}');
    }
  }

  Future<void> setupEndpoint(String code) async {
    await _seosMobileKeysPlugin.setupEndpoint(code);
  }
}