/* 
 * This file is part of Stack Wallet.
 * 
 * Copyright (c) 2023 Cypher Stack
 * All Rights Reserved.
 * The code is distributed under GPLv3 license, see LICENSE file for details.
 * Generated by Cypher Stack on 2023-05-26
 *
 */

import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:local_auth/auth_strings.dart';
import 'package:local_auth/local_auth.dart';
import 'package:stackwallet/utilities/logger.dart';

class Biometrics {
  static const integrationTestFlag =
      bool.fromEnvironment("IS_INTEGRATION_TEST");

  const Biometrics();

  Future<bool> authenticate({
    required String cancelButtonText,
    required String localizedReason,
    required String title,
  }) async {
    if (!(Platform.isIOS || Platform.isAndroid)) {
      Logging.instance.log(
          "Tried to use Biometrics.authenticate() on a platform that is not Android or iOS! ...returning false.",
          level: LogLevel.Error);
      return false;
    }
    if (integrationTestFlag) {
      Logging.instance.log(
          "Tried to use Biometrics.authenticate() during integration testing. Returning false.",
          level: LogLevel.Warning);
      return false;
    }

    final LocalAuthentication localAuth = LocalAuthentication();

    final canCheckBiometrics = await localAuth.canCheckBiometrics;
    final isDeviceSupported = await localAuth.isDeviceSupported();

    //todo: check if print needed
    // debugPrint("canCheckBiometrics: $canCheckBiometrics");
    // debugPrint("isDeviceSupported: $isDeviceSupported");

    if (canCheckBiometrics && isDeviceSupported) {
      List<BiometricType> availableSystems =
          await localAuth.getAvailableBiometrics();

      //todo: check if print needed
      // debugPrint("availableSystems: $availableSystems");

      //TODO properly handle caught exceptions
      if (Platform.isIOS) {
        if (availableSystems.contains(BiometricType.face)) {
          try {
            bool didAuthenticate = await localAuth.authenticate(
              biometricOnly: true,
              localizedReason: localizedReason,
              stickyAuth: true,
              iOSAuthStrings: const IOSAuthMessages(),
            );

            if (didAuthenticate) {
              return true;
            }
          } catch (e) {
            Logging.instance.log(
                "local_auth exception caught in Biometrics.authenticate(), e: $e",
                level: LogLevel.Error);
          }
        } else if (availableSystems.contains(BiometricType.fingerprint)) {
          try {
            bool didAuthenticate = await localAuth.authenticate(
              biometricOnly: true,
              localizedReason: localizedReason,
              stickyAuth: true,
              iOSAuthStrings: const IOSAuthMessages(),
            );

            if (didAuthenticate) {
              return true;
            }
          } catch (e) {
            Logging.instance.log(
                "local_auth exception caught in Biometrics.authenticate(), e: $e",
                level: LogLevel.Error);
          }
        }
      } else if (Platform.isAndroid) {
        if (availableSystems.contains(BiometricType.fingerprint)) {
          try {
            bool didAuthenticate = await localAuth.authenticate(
              biometricOnly: true,
              localizedReason: localizedReason,
              stickyAuth: true,
              androidAuthStrings: AndroidAuthMessages(
                biometricHint: "",
                cancelButton: cancelButtonText,
                signInTitle: title,
              ),
            );

            if (didAuthenticate) {
              return true;
            }
          } catch (e) {
            Logging.instance.log(
                "local_auth exception caught in Biometrics.authenticate(), e: $e",
                level: LogLevel.Error);
          }
        }
      }
    }

    // authentication failed
    return false;
  }
}