#import "RNLocalAuthentication.h"
#import <React/RCTUtils.h>
#import <LocalAuthentication/LocalAuthentication.h>
#import <LocalAuthentication/LAContext.h>

static NSString *const kBiometryTypeNonoe = @"none";
static NSString *const kBiometryTypeTouchId = @"touchID";
static NSString *const kBiometryTypeFaceId = @"faceID";

@interface RNLocalAuthentication ()

@property (nonatomic, strong) LAContext *context;

@end

@implementation RNLocalAuthentication

#pragma mark - Getter

- (LAContext *)context {
    if (!_context) {
        _context = [[LAContext alloc] init];
    }
    return _context;
}

RCT_EXPORT_MODULE()

- (dispatch_queue_t)methodQueue {
    return dispatch_get_main_queue();
}

RCT_EXPORT_METHOD(setLocalizedFallbackTitle
                  : (NSString*)localizedFallbackTitle
                  : (RCTPromiseResolveBlock)resolve
                  : (RCTPromiseRejectBlock)reject) {
    self.context.localizedFallbackTitle = localizedFallbackTitle;
}

RCT_EXPORT_METHOD(setLocalizedCancelTitle
                  : (NSString*)localizedCancelTitle
                  : (RCTPromiseResolveBlock)resolve
                  : (RCTPromiseRejectBlock)reject) {
    if (@available(iOS 10.0, *)) {
        self.context.localizedCancelTitle = localizedCancelTitle;
    }
}

/**
 Determines if a particular policy can be evaluated.
 */
RCT_EXPORT_METHOD(canEvaluate
                  : (NSInteger)policy
                  : (RCTPromiseResolveBlock)resolve
                  : (RCTPromiseRejectBlock)reject) {
    LAPolicy policyValue = LAPolicyDeviceOwnerAuthenticationWithBiometrics;
    if (policy == 2) {
        if (@available(iOS 9.0, *)) {
            policy = LAPolicyDeviceOwnerAuthentication;
        }
    }
    NSError *error;
    
    __weak typeof(self) weakSelf = self;
    if ([self.context canEvaluatePolicy:policyValue error:&error]) {
        NSString *supportedBiometryType = kBiometryTypeNonoe;
        if (@available(iOS 11.0, *)) {
            LABiometryType biometryType = weakSelf.context.biometryType;
            if (biometryType == LABiometryTypeFaceID) {
                supportedBiometryType = kBiometryTypeFaceId;
            } else if (biometryType == LABiometryTypeTouchID) {
                supportedBiometryType = kBiometryTypeTouchId;
            }
        } else {
            supportedBiometryType = kBiometryTypeTouchId;
        }
        resolve(supportedBiometryType);
    } else {
        reject([NSString stringWithFormat:@"%@", @(error.code)], error.localizedDescription, error);
    }
}

/**
 Evaluates the specified policy.

 @param policy NSInteger 0:LAPolicyDeviceOwnerAuthenticationWithBiometrics, 1:LAPolicyDeviceOwnerAuthentication
 @param localizedReason Application reason for authentication.
 */
RCT_EXPORT_METHOD(evaluate
                  : (NSInteger)policy
                  : (NSString*)localizedReason
                  : (RCTPromiseResolveBlock)resolve
                  : (RCTPromiseRejectBlock)reject) {
    LAPolicy policyValue = LAPolicyDeviceOwnerAuthenticationWithBiometrics;
    if (policy == 2) {
        if (@available(iOS 9.0, *)) {
            policyValue = LAPolicyDeviceOwnerAuthentication;
        }
    }
    
    [self.context evaluatePolicy:policyValue localizedReason:localizedReason reply:^(BOOL success, NSError * _Nullable error) {
        if (success) {
            resolve(@YES);
        } else {
            reject([NSString stringWithFormat:@"%@", @(error.code)], error.localizedDescription, error);
        }
    }];
}

RCT_EXPORT_METHOD(invalidate) {
    [_context invalidate];
    _context = nil;
}

@end
