#import "SeonReactNativeMobileWrapper.h"
#import <SeonSDK/SEONFingerprint.h>

#ifdef RCT_NEW_ARCH_ENABLED
// New Architecture: The class should conform to the generated protocol (NativeSeonReactNativeMobileWrapperSpec)
// and methods are implemented directly (no RCT_EXPORT macros).

@implementation SeonReactNativeMobileWrapper
RCT_EXPORT_MODULE(SeonReactNativeMobileWrapperSpec)
// Implement the TurboModule methods directly

- (void)setSessionId:(NSString *)sessionId
             resolve:(RCTPromiseResolveBlock)resolve
              reject:(RCTPromiseRejectBlock)reject {
    [[SEONFingerprint sharedManager] setSessionId:sessionId];
    resolve(nil);
}

- (void)setLoggingEnabled:(BOOL)enabled resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    [[SEONFingerprint sharedManager] setLoggingEnabled:enabled];
    resolve(nil);
}

- (void)getFingerprintBase64:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    [[SEONFingerprint sharedManager] getFingerprintBase64:^(NSString *seonFingerprint, NSError *error) {
        if (!error) {
            resolve(seonFingerprint);
        } else {
            NSString *errorMessage = error.localizedDescription;
            if (seonFingerprint != nil) {
                errorMessage = [NSString stringWithFormat:@"DESCRIPTION: %@ CODE: %li RESPONSE:%@", errorMessage, error.code, seonFingerprint];
            } else {
                errorMessage = [NSString stringWithFormat:@"SEON_ERROR_CODE:%li DESCRIPTION: %@", error.code, errorMessage];
            }
            reject(error.domain, errorMessage, error);
        }
    }];
}

- (void)startBehaviourMonitoring:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    NSError *error = [[SEONFingerprint sharedManager] startBehaviourMonitoring];
    if (!error) {
        resolve(nil);
    } else {
        reject(error.domain, [NSString stringWithFormat:@"SEON_BEHAVIOUR_ERROR CODE:%li DESCRIPTION: %@", error.code, error.localizedDescription], error);
    }
}

- (void)stopBehaviourMonitoring:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    [[SEONFingerprint sharedManager] stopBehaviourMonitoring:^(NSString *seonFingerprint, NSError *error) {
        if (!error) {
            resolve(seonFingerprint);
        } else {
            NSString *errorMessage = error.localizedDescription;
            if (seonFingerprint != nil) {
                errorMessage = [NSString stringWithFormat:@"DESCRIPTION: %@ CODE: %li RESPONSE:%@", errorMessage, error.code, seonFingerprint];
            } else {
                errorMessage = [NSString stringWithFormat:@"SEON_ERROR_CODE:%li DESCRIPTION: %@", error.code, errorMessage];
            }
            reject(error.domain, errorMessage, error);
        }
    }];
}

- (void)setGeolocationEnabled:(BOOL)enabled resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
    @try {
        [[SEONFingerprint sharedManager] setGeolocationEnabled:enabled];
        resolve(nil);
    }
    @catch (NSException *exception) {
        reject(@"GEOLOCATION_CONFIG_ERROR", exception.reason, nil);
    }
}

- (void)setGeoLocationConfig:(JS::NativeSeonReactNativeMobileWrapper::SeonGeolocationConfig &)jsConfig
                     resolve:(RCTPromiseResolveBlock)resolve
                      reject:(RCTPromiseRejectBlock)reject {
    @try {
        SEONGeolocationConfig *geoConfig = [[SEONGeolocationConfig alloc] init];
        
        // Handle optional values with proper unwrapping
        if (jsConfig.geolocationServiceTimeoutMs().has_value()) {
            geoConfig.geolocationServiceTimeoutMs = (int)jsConfig.geolocationServiceTimeoutMs().value();
        }
        
        if (jsConfig.geolocationEnabled().has_value()) {
            geoConfig.geolocationEnabled = jsConfig.geolocationEnabled().value();
        }
        
        if (jsConfig.prefetchEnabled().has_value()) {
            geoConfig.prefetchEnabled = jsConfig.prefetchEnabled().value();
        }
        
        if (jsConfig.maxGeoLocationCacheAgeSec().has_value()) {
            geoConfig.maxGeoLocationCacheAgeSec = (int)jsConfig.maxGeoLocationCacheAgeSec().value();
        }
        
        [[SEONFingerprint sharedManager] setGeolocationConfig:geoConfig];
        resolve(nil);
    }
    @catch (NSException *exception) {
        reject(@"SEON_GEO_CONFIG_EXCEPTION", exception.reason, nil);
    }
}
// Provide the TurboModule instance as required by the new architecture.
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
    return std::make_shared<facebook::react::NativeSeonReactNativeMobileWrapperSpecJSI>(params);
}

@end

#else
// Old Architecture: Use RCT_EXPORT_MODULE and RCT_EXPORT_METHOD macros

@implementation SeonReactNativeMobileWrapper

RCT_EXPORT_MODULE(SeonReactNativeMobileWrapperSpec)

RCT_EXPORT_METHOD(setSessionId:(NSString *)sessionId
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
    [[SEONFingerprint sharedManager] setSessionId:sessionId];
    resolve(nil);
}

RCT_EXPORT_METHOD(setLoggingEnabled:(BOOL)enabled
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
    [[SEONFingerprint sharedManager] setLoggingEnabled:enabled];
    resolve(nil);
}

RCT_EXPORT_METHOD(getFingerprintBase64:(RCTPromiseResolveBlock)resolve
                 reject:(RCTPromiseRejectBlock)reject)
{
      [[SEONFingerprint sharedManager] getFingerprintBase64:^(NSString *seonFingerprint, NSError *error) {
        if (!error){
            resolve(seonFingerprint);
        } else {
            NSString *errorMessage = error.localizedDescription;
            if (seonFingerprint != nil){
                errorMessage = [NSString stringWithFormat:@"DESCRIPTION: %@ CODE: %li RESPONSE:%@", errorMessage, error.code, seonFingerprint];
            } else {
                errorMessage = [NSString stringWithFormat:@"SEON_ERROR_CODE:%li DESCRIPTION: %@", error.code, errorMessage];
            }
            reject(error.domain, errorMessage, error);
        }
    }];
}

RCT_EXPORT_METHOD(startBehaviourMonitoring:(RCTPromiseResolveBlock)resolve
                      reject:(RCTPromiseRejectBlock)reject)
{
    NSError *error = [[SEONFingerprint sharedManager] startBehaviourMonitoring];
    if (!error) {
        resolve(nil);
    } else {
        reject(error.domain, [NSString stringWithFormat:@"SEON_BEHAVIOUR_ERROR CODE:%li DESCRIPTION: %@", error.code, error.localizedDescription], error);
    }
}

RCT_EXPORT_METHOD(stopBehaviourMonitoring:(RCTPromiseResolveBlock)resolve
                      reject:(RCTPromiseRejectBlock)reject)
{
    [[SEONFingerprint sharedManager] stopBehaviourMonitoring:^(NSString *seonFingerprint, NSError *error) {
        if (!error) {
            resolve(seonFingerprint);
        } else {
            NSString *errorMessage = error.localizedDescription;
            if (seonFingerprint != nil) {
                errorMessage = [NSString stringWithFormat:@"DESCRIPTION: %@ CODE: %li RESPONSE:%@", errorMessage, error.code, seonFingerprint];
            } else {
                errorMessage = [NSString stringWithFormat:@"SEON_ERROR_CODE:%li DESCRIPTION: %@", error.code, errorMessage];
            }
            reject(error.domain, errorMessage, error);
        }
    }];
}

RCT_EXPORT_METHOD(setGeolocationEnabled:(BOOL)enabled
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
    @try {
        [[SEONFingerprint sharedManager] setGeolocationEnabled:enabled];
        resolve(nil);
    }
    @catch (NSException *exception) {
        reject(@"GEOLOCATION_CONFIG_ERROR", exception.reason, nil);
    }
}

RCT_EXPORT_METHOD(setGeoLocationConfig:(NSDictionary *)config
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
    @try {
        SEONGeolocationConfig *geoConfig = [[SEONGeolocationConfig alloc] init];
        geoConfig.geolocationServiceTimeoutMs = [[config valueForKey:@"geolocationServiceTimeoutMs"] intValue];
        geoConfig.geolocationEnabled = [[config valueForKey:@"geolocationEnabled"] boolValue];
        geoConfig.prefetchEnabled = [[config valueForKey:@"prefetchEnabled"] boolValue];
        geoConfig.maxGeoLocationCacheAgeSec = [[config valueForKey:@"maxGeoLocationCacheAgeSec"] intValue];
        if (geoConfig) {
            [[SEONFingerprint sharedManager] setGeolocationConfig:geoConfig];
        } else {
            reject(@"SEON_GEO_CONFIG_ERROR", @"The provided geolocation config object is null or invalid.", nil);
        }
        resolve(nil);
    }
    @catch (NSException *exception) {
        reject(@"SEON_GEO_CONFIG_EXCEPTION", exception.reason, nil);
    }
}

@end

#endif
