import 'package:pigeon/pigeon.dart';

enum MobileKeysScanMode { optimizePerformance, optimizePowerConsumption }

enum OpeningType {
  unknown,
  proximity,
  motion,
  seamless,
  applicationSpecific,
  enhancedTap,
}

enum MobileKeysInfoType {
  /// Bluetooth services is not authorized by user. Recommended user action is to change permissions.
  bleNotSupported,

  /// Bluetooth services is not authorized by this device. Recommended user action is to change device.
  bleTurnedOff,

  /// Location services is not enabled in app project settings. Recommended developer action is to change project settings.
  locationServicesNotEnabled,

  /// Location services authorization is not determined by user. Recommended developer action is to call requestAlwaysAuthorization.
  locationServicesNotDetermined,

  /// Location services is not authorized by user. Recommended user action is to change permissions.
  locationServicesTurnedOff,

  /// CLBeaconRegion monitoring or ranging is not supported by this device. Recommended user action is to change device.
  locationMonitoringNotSupported,

  /// CLBeaconRegion monitoring or ranging is not authorized by the user. Recommended user action is to change permissions.
  locationMonitoringTurnedOff,

  /// Passcode may be turned off. This cannot be verified 100% reliably, but this could be an indication that the phone is not protected by a password.
  passcodeWarning,

  /// Bluetooth sharing authorization for BLE Peripheral mode has not been granted. This should only happen when using Enhanced Tap. Recommended user action is to go to App System Settings and enable Bluetooth Sharing.
  bleSharingTurnedOff,
}

enum MobileKeysEnvironmentType {
  prod,
  demo,
  test,
  dev,
  local,
  staging,
  acceptance,
  unknown,
}

enum MobileKeysReaderType {
  blePeripheral,
  bleCentral,
  httpRest,
}

enum BleProtocol {
  legacy,
  v1,
  unknown,
}

class MobileKeysOpeningType {
  final OpeningType openingType;

  MobileKeysOpeningType(this.openingType);
}

class DataTypeDate {
  final String date;
  final String format;

  DataTypeDate(this.date, this.format);
}

class MobileKeysKey {
  final int credentialType;
  final DataTypeDate? beginDate;
  final DataTypeDate? endDate;
  final String? keyId;
  final String? externalId;
  final String? label;
  final String? configUrl;
  final String? readbackUrl;
  final String? issuer;
  final String? keyType;
  final String? cardNumber;
  final bool active;

  MobileKeysKey(
      this.label,
      this.cardNumber,
      this.credentialType,
      this.beginDate,
      this.endDate,
      this.keyId,
      this.externalId,
      this.configUrl,
      this.readbackUrl,
      this.issuer,
      this.keyType,
      this.active);
}

class MobileKeysEndpointInfo {
  final int endpointId;
  final MobileKeysEnvironmentType mobileKeysEnvironmentType;
  final String seosAppletVersion;
  final String fileSystemAppletVersion;
  final String toolsAppletVersion;
  final String javaCardVersion;
  final String optionFlags;
  final int allocatedFileSystemSize;
  final int currentTopOfFileSystem;
  final int snmpBufferSize;
  final int remainingEPROMSize;
  final int remainingTransientObjectSpace;
  final int? hashAlg;
  final int? encAlg;
  final DataTypeDate? lastServerSyncDate;

  MobileKeysEndpointInfo(
      this.endpointId,
      this.mobileKeysEnvironmentType,
      this.seosAppletVersion,
      this.fileSystemAppletVersion,
      this.toolsAppletVersion,
      this.javaCardVersion,
      this.optionFlags,
      this.allocatedFileSystemSize,
      this.currentTopOfFileSystem,
      this.snmpBufferSize,
      this.remainingEPROMSize,
      this.remainingTransientObjectSpace,
      this.hashAlg,
      this.encAlg,
      this.lastServerSyncDate);
}

class MobileKeysLastAuthenticationInfo {
  final MobileKeysKey lastAuthenticatedMobileKey;
  final bool isModified;
  final int authenticationCounter;

  MobileKeysLastAuthenticationInfo(this.lastAuthenticatedMobileKey,
      this.isModified, this.authenticationCounter);
}

class MobileKeysTimeoutConfiguration {
  final double maxTimeBetweenFragments;
  final double maxTimeBetweenApdus;
  final double maxConnectionTime;

  MobileKeysTimeoutConfiguration(this.maxTimeBetweenFragments,
      this.maxTimeBetweenApdus, this.maxConnectionTime);
}

class MobileKeysRssiMeasurement {
  final int rssiValue;
  final double measuredAtIntervalSince1970;

  MobileKeysRssiMeasurement(this.rssiValue, this.measuredAtIntervalSince1970);
}

class MobileKeysReader {
  final Map<int?, int?> rssiValueLimitsForOpeningTypeKeys;
  final String? uuid;
  final bool readerCanConnect;
  final MobileKeysRssiMeasurement? latestRssiMeasurement;
  final DataTypeDate? lastSuccessfulConnection;
  final String? name;
  final String? localName;
  final List<int?> supportedOpeningTypes;
  final DataTypeDate? lastRSSIUpdate;
  final MobileKeysReaderType readerType;
  final Uint8List? optionalScanResponseData;
  final Uint8List? serialNumberData;
  final Uint8List? appSpecificData;
  final BleProtocol protocolVersion;
  final int txPowerLevel;

  MobileKeysReader(
    this.rssiValueLimitsForOpeningTypeKeys,
    this.uuid,
    this.readerCanConnect,
    this.latestRssiMeasurement,
    this.lastSuccessfulConnection,
    this.name,
    this.localName,
    this.supportedOpeningTypes,
    this.lastRSSIUpdate,
    this.readerType,
    this.optionalScanResponseData,
    this.serialNumberData,
    this.appSpecificData,
    this.protocolVersion,
    this.txPowerLevel,
  );
}

@HostApi()
abstract class AppUsageAPI {
  @async
  void startUp(Map<String?, Object?> options);

  @async
  bool deviceHasBluetoothTurnedOn();

  @async
  bool deviceSupportsBluetoothLowEnergy();

  @async
  bool isEndpointSetup();

  @async
  void setupEndpoint(String invitationCode);

  @async
  void updateEndpoint();

  @async
  void terminateEndpoint();

  @async
  List<MobileKeysKey> listMobileKeys();

  @async
  bool activateMobileKey(MobileKeysKey key);

  @async
  bool deactivateMobileKey(MobileKeysKey key);

  @async
  String generateOTPForKey(MobileKeysKey key);

  @async
  int otpCounterForKey(MobileKeysKey key);

  @async
  MobileKeysEndpointInfo endpointInfo();

  @async
  List<MobileKeysInfoType> healthCheck();

  @async
  String apiVersion();

  @async
  bool isScanning();

  @async
  void startReaderScan(
      MobileKeysScanMode mode,
      List<MobileKeysOpeningType> supportedOpeningTypes,
      List<int> lockServiceCodes);

  @async
  void setSupportedOpeningTypes(
      List<MobileKeysOpeningType> supportedOpeningTypes);

  @async
  void setTimeoutConfiguration(
      MobileKeysTimeoutConfiguration timeoutConfiguration);

  @async
  void stopReaderScan();

  @async
  MobileKeysLastAuthenticationInfo lastAuthenticationInfo();

  @async
  List<MobileKeysReader> listReaders();

  @async
  MobileKeysReader? closestReaderWithinRangeOfOpeningType(
      MobileKeysOpeningType type);

  @async
  void connect(
      MobileKeysReader reader, MobileKeysOpeningType openingType);

  @async
  void forceConnect(
      MobileKeysReader reader, MobileKeysOpeningType openingType);

  @async
  void cancelReaderConnection(MobileKeysReader reader);

  @async
  void openClosestReader();

  @async
  void setRootOpeningTrigger();

  @async
  void removeRootOpeningTrigger();

  @async
  bool isAnalyticsEnabled();

  @async
  void analytics(bool enable);
}