#import "PaygilantWrapper.h"

#import <UIKit/UIKit.h>
#import <PaygilantSDK/PaygilantSDK-Swift.h>

@interface PaygilantWrapper ()
@end

@implementation PaygilantWrapper
RCT_EXPORT_MODULE(PaygilantWrapper)

NSString *_reactNativeVersion;
BOOL callSetApproveBefore = NO;

RCT_EXPORT_METHOD(initialize:(NSString * _Nonnull)serverUrl
                  clientSessionId:(NSString * _Nullable)clientSessionId
                  toAskPermissions:(BOOL)toAskPermissions
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {

    CrossPlatformType crossPlatformType = CrossPlatformTypeReactNative;
    CrossPlatformVersion *crossPlatformVersion = [[CrossPlatformVersion alloc] initWithVersion:_reactNativeVersion
                                                                                crossPlatformType:crossPlatformType];
    // Call setup with serverUrl and clientSessionId, using completion handlers
    [PaygilantManager.shared setupWithServerUrl:serverUrl clientSessionId:clientSessionId toAskPermissions:toAskPermissions crossPlatform:crossPlatformVersion success:^{
        // NSLog(@"Initialization succeeded");
        resolve(@(YES));  // Resolve the promise if initialization succeeds
    } failure:^(NSString *errorDescription) {
        // NSLog(@"Error: %@", errorDescription);
        NSError *error = [NSError errorWithDomain:@"PaygilantInitialization" code:500 userInfo:@{NSLocalizedDescriptionKey: errorDescription}];
        reject(@"error", errorDescription, error);  // Reject the promise with an error description
    }];
}

// Method to set the React Native version
RCT_EXPORT_METHOD(setReactNativeVersion:(NSString * _Nonnull)version
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    @try {
        // Store the version in the internal variable
        _reactNativeVersion = version;
        // NSLog(@"React Native Version set to: %@", version);
        resolve(nil); // Resolve immediately
    } @catch (NSException *exception) {
        // Handle potential exceptions
        NSError *error = [NSError errorWithDomain:@"PaygilantErrorDomain"
                                             code:500
                                         userInfo:@{NSLocalizedDescriptionKey: exception.reason}];
        reject(@"error", exception.reason, error);
    }
}
+ (BOOL) requiresMainQueueSetup {
  return YES;
}

RCT_EXPORT_METHOD(setApprovePolicy:(BOOL)approvePolicy resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {

    [PaygilantManager.shared setApprovePolicy:approvePolicy];
    resolve(nil);
}

RCT_EXPORT_METHOD(askPaygilantPermissions:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {

    [PaygilantManager.shared askPaygilantPermissions];
    resolve(nil);
}
RCT_EXPORT_METHOD(logout:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {

    [PaygilantManager.shared logout];
    resolve(nil);
}
RCT_EXPORT_METHOD(getSessionId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    [PaygilantManager.shared getSessionIdWithSessionIdCallback:^(NSString *sessionId) {
        if (sessionId && sessionId.length > 0) {
            resolve(sessionId);
        } else {
            // Return "no_session_id" if the session ID is not available
            resolve(@"no_session_id");
        }
    }];
}

RCT_EXPORT_METHOD(isApprovePolicy: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
   BOOL type = [PaygilantManager isApprovePolicy];
    resolve(@(type));
}

RCT_EXPORT_METHOD(startNewScreenListener:( NSString * _Nonnull)type paygilantListenerID:(int)paygilantListenerID resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    if (!callSetApproveBefore){
        callSetApproveBefore = YES;
        [PaygilantManager.shared setApprovePolicy:true];
    }
}

RCT_EXPORT_METHOD(getDeviceId: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
    resolve(@"no_device_id");
}
RCT_EXPORT_METHOD(startUserVerification:(NSString *)userId
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  // must be on main queue to present UI
  dispatch_async(dispatch_get_main_queue(), ^{
    UIViewController *rootVC = UIApplication.sharedApplication.delegate.window.rootViewController;
    NSError *swiftError = nil;

    // note: "error:" comes before "callback:"
    [PaygilantManager.shared startUserVerificationFrom:rootVC
                                              userId:userId
                                               error:&swiftError
                                              callback:^(BOOL success) {
        // if the Swift method threw, callback won’t fire
        if (success){
            resolve(@"true");
        }else{
            resolve(@"false");
        }
    }];

    if (swiftError) {
      // Map any thrown PaygilantError into a JS rejection
      reject(@"error", swiftError.localizedDescription, swiftError);
    }
  });
}

// Expose setClientSessionId to JS as a Promise<string>
RCT_EXPORT_METHOD(setClientSessionId:(NSString *)clientSessionId
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  // Swift signature: public func setClientSessionId(_ clientSessionId:String, callback:@escaping(String)->Void)
  [PaygilantManager.shared setClientSessionId:clientSessionId callback:^(NSString *sessionId) {
    if (sessionId && sessionId.length > 0) {
      resolve(sessionId);
    } else {
      resolve(@"no_session_id");
    }
  }];
}

- (void)getSessionId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    [PaygilantManager.shared getSessionIdWithSessionIdCallback:^(NSString *sessionId) {
        if (sessionId && sessionId.length > 0) {
            resolve(sessionId);
        } else {
            // Return "no_session_id" if the session ID is not available
            resolve(@"no_session_id");
        }
    }];
}


- (void)isApprovePolicy:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    BOOL type = [PaygilantManager.shared isApprovePolicy];
     resolve(@(type));
}
- (void)setReactNativeVersion:(NSString *)version resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    @try {
        // Store the version in the internal variable
        _reactNativeVersion = version;
        // NSLog(@"React Native Version set to: %@", version);
        resolve(nil); // Resolve immediately
    } @catch (NSException *exception) {
        // Handle potential exceptions
        NSError *error = [NSError errorWithDomain:@"PaygilantErrorDomain"
                                             code:500
                                         userInfo:@{NSLocalizedDescriptionKey: exception.reason}];
        reject(@"error", exception.reason, error);
    }
}

- (void)initialize:(NSString *)serverUrl clientSessionId:clientSessionId toAskPermissions:(BOOL)toAskPermissions resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    
    CrossPlatformType crossPlatformType = CrossPlatformTypeReactNative;
    CrossPlatformVersion *crossPlatformVersion = [[CrossPlatformVersion alloc] initWithVersion:_reactNativeVersion
                                                                                crossPlatformType:crossPlatformType];
    // Call setup with serverUrl and clientSessionId, using completion handlers
    [PaygilantManager.shared setupWithServerUrl:serverUrl clientSessionId:clientSessionId toAskPermissions:toAskPermissions crossPlatform:crossPlatformVersion success:^{
        // NSLog(@"Initialization succeeded");
        resolve(@(YES));  // Resolve the promise if initialization succeeds
    } failure:^(NSString *errorDescription) {
        // NSLog(@"Error: %@", errorDescription);
        NSError *error = [NSError errorWithDomain:@"PaygilantInitialization" code:500 userInfo:@{NSLocalizedDescriptionKey: errorDescription}];
        reject(@"error", errorDescription, error);  // Reject the promise with an error description
    }];
}


- (void)setApprovePolicy:(BOOL)approvePolicy resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
//     [PaygilantManager.shared set :approvePolicy];
    [PaygilantManager.shared setApprovePolicy:approvePolicy];
    resolve(nil);
}
- (void)askPaygilantPermissions:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
//     [PaygilantManager.shared set :approvePolicy];
    [PaygilantManager.shared askPaygilantPermissions];
    resolve(nil);
}

- (void)logout:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
//     [PaygilantManager.shared set :approvePolicy];
    [PaygilantManager.shared logout];
    resolve(nil);
}

- (void)startNewScreenListener:(NSString *)type screenId:(double)screenId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    if (!callSetApproveBefore){
        callSetApproveBefore = YES;
        [PaygilantManager.shared setApprovePolicy:true];
    }
}


- (void)getDeviceId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    resolve(@"no_device_id");
}

- (void)setClientSessionId:(NSString *)clientSessionId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject{
    [PaygilantManager.shared setClientSessionId:clientSessionId callback:^(NSString *sessionId) {
      if (sessionId && sessionId.length > 0) {
        resolve(sessionId);
      } else {
        resolve(@"no_session_id");
      }
    }];
}
- (void) startUserVerification:(NSString *)userId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject{
    // must be on main queue to present UI
    dispatch_async(dispatch_get_main_queue(), ^{
      UIViewController *rootVC = UIApplication.sharedApplication.delegate.window.rootViewController;
      NSError *swiftError = nil;

      // note: "error:" comes before "callback:"
      [PaygilantManager.shared startUserVerificationFrom:rootVC
                                                userId:userId
                                                 error:&swiftError
                                              callback:^(BOOL success) {
        // if the Swift method threw, callback won’t fire
        if (success){
              resolve(@"true");
          }else{
              resolve(@"false");
          }
      }];

      if (swiftError) {
        // Map any thrown PaygilantError into a JS rejection
        reject(@"error", swiftError.localizedDescription, swiftError);
      }
    });
}

// Don't compile this code when we build for the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
    return std::make_shared<facebook::react::NativePaygilantWrapperSpecJSI>(params);
}
#endif

@end
