//
//  RPRReproReactBridge.mm
//  RPRReproReactBridge
//
//  Created by Markus Wanke on 2018/08/08.
//  Copyright © 2018 Repro Inc. All rights reserved.
//


#import "RPRReproReactBridge.h"
#import "RPRReproReactBridgeImpl.h"
#import <Repro/Repro.h>
#import <Repro/RPRRemoteConfig.h>
#import <Repro/RPRNewsFeedEntry.h>
#import <Repro/RPRUserProfileTypes.h>

// ReactNative Version >= 0.41
#if __has_include(<React/RCTConvert.h>)
#import <React/RCTConvert.h>

// ReactNative Version < 0.41
#elif __has_include("RCTConvert.h")
#import "RCTConvert.h"

// if ReactNative is a cocoapod and the project has swift enabled
#elif __has_include("React/RCTConvert.h")
#import "React/RCTConvert.h"

#else
#error "Can't find RCTConvert.h anywhere."
#endif




// ReactNative Version >= 0.41
#if __has_include(<React/RCTVersion.h>)
#import <React/RCTVersion.h>

// ReactNative Version < 0.41
#elif __has_include("RCTVersion.h")
#import "RCTVersion.h"

// if ReactNative is a cocoapod and the project has swift enabled
#elif __has_include("React/RCTVersion.h")
#import "React/RCTVersion.h"

#else
    #define RPR_CANT_DETERMINE_RN_VERSION 1
#endif



static NSObject*
safe_value(id value)
{
    return (value != nil) ? value : [NSNull null];
}

@implementation RCTConvert (RPRLogLevel)
    RCT_ENUM_CONVERTER(RPRLogLevel, (@{
        @"LOGLEVEL_DEBUG"  : @(RPRLogLevelDebug),
        @"LOGLEVEL_INFO"   : @(RPRLogLevelInfo),
        @"LOGLEVEL_WARN"   : @(RPRLogLevelWarn),
        @"LOGLEVEL_ERROR"  : @(RPRLogLevelError),
        @"LOGLEVEL_NONE"   : @(RPRLogLevelNone)}),
    RPRLogLevelNone, integerValue)
@end

@implementation RCTConvert (RPRUserProfileGender)
    RCT_ENUM_CONVERTER(RPRUserProfileGender, (@{
        @"GENDER_OTHER"    : @(RPRUserProfileGenderOther),
        @"GENDER_MALE"     : @(RPRUserProfileGenderMale),
        @"GENDER_FEMALE"   : @(RPRUserProfileGenderFemale)}),
    RPRUserProfileGenderOther, integerValue)
@end

@implementation RCTConvert (RPRRemoteConfigFetchStatus)
    RCT_ENUM_CONVERTER(RPRRemoteConfigFetchStatus, (@{
        @"REMOTE_CONFIG_SUCCESS"              : @(RPRRemoteConfigFetchStatusSuccess),
        @"REMOTE_CONFIG_TIMEOUT_REACHED"      : @(RPRRemoteConfigFetchStatusTimeoutReached),
        @"REMOTE_CONFIG_ALREADY_FETCHED"      : @(RPRRemoteConfigFetchStatusAlreadyFetched)}),
    RPRRemoteConfigFetchStatusTimeoutReached, integerValue)
@end

@implementation RCTConvert (RPRCampaignType)
    RCT_ENUM_CONVERTER(RPRCampaignType, (@{
        @"CAMPAIGN_TYPE_UNKNOWN"              : @(RPRCampaignTypeUnknown),
        @"CAMPAIGN_TYPE_PUSH_NOTIFICATION"    : @(RPRCampaignTypePushNotification),
        @"CAMPAIGN_TYPE_IN_APP_MESSAGE"       : @(RPRCampaignTypeInAppMessage),
        @"CAMPAIGN_TYPE_WEB_MESSAGE"          : @(RPRCampaignTypeWebMessage)}),
    RPRCampaignTypePushNotification, integerValue)
@end

@implementation RCTConvert (RPRUserProfilePrefecture)
    RCT_ENUM_CONVERTER(RPRUserProfilePrefecture, (@{
        @"PREFECTURE_HOKKAIDO" : @(RPRUserProfilePrefectureHokkaido),
        @"PREFECTURE_AOMORI" : @(RPRUserProfilePrefectureAomori),
        @"PREFECTURE_IWATE" : @(RPRUserProfilePrefectureIwate),
        @"PREFECTURE_MIYAGI" : @(RPRUserProfilePrefectureMiyagi),
        @"PREFECTURE_AKITA" : @(RPRUserProfilePrefectureAkita),
        @"PREFECTURE_YAMAGATA" : @(RPRUserProfilePrefectureYamagata),
        @"PREFECTURE_FUKUSHIMA" : @(RPRUserProfilePrefectureFukushima),
        @"PREFECTURE_IBARAKI" : @(RPRUserProfilePrefectureIbaraki),
        @"PREFECTURE_TOCHIGI" : @(RPRUserProfilePrefectureTochigi),
        @"PREFECTURE_GUNMA" : @(RPRUserProfilePrefectureGunma),
        @"PREFECTURE_SAITAMA" : @(RPRUserProfilePrefectureSaitama),
        @"PREFECTURE_CHIBA" : @(RPRUserProfilePrefectureChiba),
        @"PREFECTURE_TOKYO" : @(RPRUserProfilePrefectureTokyo),
        @"PREFECTURE_KANAGAWA" : @(RPRUserProfilePrefectureKanagawa),
        @"PREFECTURE_NIIGATA" : @(RPRUserProfilePrefectureNiigata),
        @"PREFECTURE_TOYAMA" : @(RPRUserProfilePrefectureToyama),
        @"PREFECTURE_ISHIKAWA" : @(RPRUserProfilePrefectureIshikawa),
        @"PREFECTURE_FUKUI" : @(RPRUserProfilePrefectureFukui),
        @"PREFECTURE_YAMANASHI" : @(RPRUserProfilePrefectureYamanashi),
        @"PREFECTURE_NAGANO" : @(RPRUserProfilePrefectureNagano),
        @"PREFECTURE_GIFU" : @(RPRUserProfilePrefectureGifu),
        @"PREFECTURE_SHIZUOKA" : @(RPRUserProfilePrefectureShizuoka),
        @"PREFECTURE_AICHI" : @(RPRUserProfilePrefectureAichi),
        @"PREFECTURE_MIE" : @(RPRUserProfilePrefectureMie),
        @"PREFECTURE_SHIGA" : @(RPRUserProfilePrefectureShiga),
        @"PREFECTURE_KYOTO" : @(RPRUserProfilePrefectureKyoto),
        @"PREFECTURE_OSAKA" : @(RPRUserProfilePrefectureOsaka),
        @"PREFECTURE_HYOGO" : @(RPRUserProfilePrefectureHyogo),
        @"PREFECTURE_NARA" : @(RPRUserProfilePrefectureNara),
        @"PREFECTURE_WAKAYAMA" : @(RPRUserProfilePrefectureWakayama),
        @"PREFECTURE_TOTTORI" : @(RPRUserProfilePrefectureTottori),
        @"PREFECTURE_SHIMANE" : @(RPRUserProfilePrefectureShimane),
        @"PREFECTURE_OKAYAMA" : @(RPRUserProfilePrefectureOkayama),
        @"PREFECTURE_HIROSHIMA" : @(RPRUserProfilePrefectureHiroshima),
        @"PREFECTURE_YAMAGUCHI" : @(RPRUserProfilePrefectureYamaguchi),
        @"PREFECTURE_TOKUSHIMA" : @(RPRUserProfilePrefectureTokushima),
        @"PREFECTURE_KAGAWA" : @(RPRUserProfilePrefectureKagawa),
        @"PREFECTURE_EHIME" : @(RPRUserProfilePrefectureEhime),
        @"PREFECTURE_KOCHI" : @(RPRUserProfilePrefectureKochi),
        @"PREFECTURE_FUKUOKA" : @(RPRUserProfilePrefectureFukuoka),
        @"PREFECTURE_SAGA" : @(RPRUserProfilePrefectureSaga),
        @"PREFECTURE_NAGASAKI" : @(RPRUserProfilePrefectureNagasaki),
        @"PREFECTURE_KUMAMOTO" : @(RPRUserProfilePrefectureKumamoto),
        @"PREFECTURE_OITA" : @(RPRUserProfilePrefectureOita),
        @"PREFECTURE_MIYAZAKI" : @(RPRUserProfilePrefectureMiyazaki),
        @"PREFECTURE_KAGOSHIMA" : @(RPRUserProfilePrefectureKagoshima),
        @"PREFECTURE_OKINAWA" : @(RPRUserProfilePrefectureOkinawa)}),
    RPRUserProfilePrefectureHokkaido, integerValue)
@end


@interface RPRRemoteConfigBridge ()

@property (nonatomic) RPRRemoteConfig* remoteConfig;

@end

@implementation RPRRemoteConfigBridge
{
  RPRReproReactBridgeImpl *_reproImpl;
}

RCT_EXPORT_MODULE(ReproRemoteConfigBridge)

- (instancetype)init
{
    self = [super init];
    if (self) {
      _reproImpl = [[RPRReproReactBridgeImpl alloc] init];
    }

    return self;
}

- (NSDictionary *)constantsToExport
{
    NSDictionary *fetchStatusConstants = @{
        @"REMOTE_CONFIG_SUCCESS"            : @(RPRRemoteConfigFetchStatusSuccess),
        @"REMOTE_CONFIG_TIMEOUT_REACHED"    : @(RPRRemoteConfigFetchStatusTimeoutReached),
        @"REMOTE_CONFIG_ALREADY_FETCHED"    : @(RPRRemoteConfigFetchStatusAlreadyFetched),
    };
    NSMutableDictionary *mergedDict = [fetchStatusConstants mutableCopy];
    [mergedDict addEntriesFromDictionary:@{
        @"FETCH_STATUS": fetchStatusConstants,
    }];
    NSDictionary *finalDict = [mergedDict copy];
    return finalDict;
};

- (NSDictionary *)getConstants
{
  return [self constantsToExport];
}


+ (BOOL)requiresMainQueueSetup
{
    return YES;  // needed because we override `constantsToExport`
}

- (NSDictionary *)toDictionary:(NSDictionary<NSString *, RPRRemoteConfigValue *> *)values
{
    NSMutableDictionary *dict = [NSMutableDictionary.alloc initWithCapacity:values.count];

    for (NSString* key in values.allKeys) {
        RPRRemoteConfigValue* value = values[key];
        if (value.stringValue) {
            [dict setObject:value.stringValue forKey:key];
        }
    }

    return [NSDictionary.alloc initWithDictionary: dict];
}


#ifdef RCT_NEW_ARCH_ENABLED

- (void)fetch:(double)timeout callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl fetch:timeout completionHandler:callback];
}

- (void)activateFetched
{
    [_reproImpl activateFetched];
}

- (void)setDefaultsFromDictionary:(NSDictionary<NSString *, id> *) json
{
    [_reproImpl setDefaultsFromDictionary:json];
}

- (void)setDefaultsFromJsonString:(NSString *)string
{
    [_reproImpl setDefaultsFromJsonString:string];
}

- (void)getValue:(NSString*)key callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl getValue:key callback:callback];
}

- (void)getAllValues:(RCTResponseSenderBlock)callback
{
    [_reproImpl getAllValues:callback];
}

- (void)getAllValuesWithPrefix:(NSString*)key callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl getAllValuesWithPrefix:key callback:callback];
}

- (void)getLocalDefaultValue:(NSString*)key callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl getLocalDefaultValue:key callback:callback];
}

- (void)forceReset
{
    [_reproImpl forceReset];
}

#else

RCT_EXPORT_METHOD(fetch:(double)timeout completionHandler:(RCTResponseSenderBlock)callback)
{
    [_reproImpl fetch:timeout completionHandler:callback];
}

RCT_EXPORT_METHOD(activateFetched)
{
    [_reproImpl activateFetched];
}

RCT_EXPORT_METHOD(setDefaultsFromDictionary:(NSDictionary<NSString *, id> *) json)
{
    [_reproImpl setDefaultsFromDictionary:json];
}

RCT_EXPORT_METHOD(setDefaultsFromJsonString:(NSString *)string)
{
    [_reproImpl setDefaultsFromJsonString:string];
}

RCT_EXPORT_METHOD(getValue:(NSString*)key callback:(RCTResponseSenderBlock)callback)
{
    [_reproImpl getValue:key callback:callback];
}

RCT_EXPORT_METHOD(getAllValues:(RCTResponseSenderBlock)callback)
{
    [_reproImpl getAllValues:callback];
}

RCT_EXPORT_METHOD(getAllValuesWithPrefix:(NSString*)key callback:(RCTResponseSenderBlock)callback)
{
    [_reproImpl getAllValuesWithPrefix:key callback:callback];
}

RCT_EXPORT_METHOD(getLocalDefaultValue:(NSString*)key callback:(RCTResponseSenderBlock)callback)
{
    [_reproImpl getLocalDefaultValue:key callback:callback];
}

RCT_EXPORT_METHOD(forceReset)
{
    [_reproImpl forceReset];
}

#endif

#if RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
    return std::make_shared<facebook::react::NativeReproRemoteConfigBridgeSpecJSI>(params);
}
#endif

@end




@interface Repro (NonPublicApi)
+ (void)_passRuntimeValues:(nonnull NSDictionary<NSString *, NSString *> *)values;
@end




#ifndef RPR_CANT_DETERMINE_RN_VERSION
static NSString *get_react_native_version()
{
// see: https://github.com/facebook/react-native/commit/30469ed00170a74743d2ba5aadce61aae742715c#
#ifdef RCT_REACT_NATIVE_VERSION
    NSDictionary *vermap = RCT_REACT_NATIVE_VERSION;
    return [NSString stringWithFormat:@"%@.%@.%@",
            vermap[@"major"],
            vermap[@"minor"],
            vermap[@"patch"]];

#else
    NSDictionary *vermap = RCTGetReactNativeVersion();
    return [NSString stringWithFormat:@"%@.%@.%@",
            vermap[RCTVersionMajor],
            vermap[RCTVersionMinor],
            vermap[RCTVersionPatch]];

#endif
}
#endif


@implementation RPRReproReactBridge
{
  RPRReproReactBridgeImpl *_reproImpl;
}

RCT_EXPORT_MODULE(ReproReactBridgeModule)

- (instancetype)init
{
    self = [super init];
    if (self) {
      _reproImpl = [[RPRReproReactBridgeImpl alloc] init];
    }

    if ([Repro respondsToSelector:@selector(_passRuntimeValues:)]) {
         [Repro _passRuntimeValues:@{
             @"sub_sdk_platform":            @"react_native",
#ifndef RPR_CANT_DETERMINE_RN_VERSION
             @"sub_sdk_platform_version":    get_react_native_version(),
#endif
             @"sub_sdk_bridge_version":      [NSString stringWithUTF8String:REPRO_REACT_NATIVE_BRIDGE_VERSION],
         }];
    }

    return self;
}

- (NSDictionary *)constantsToExport
{
    return @{
        @"LOGLEVEL_DEBUG"  : @(RPRLogLevelDebug),
        @"LOGLEVEL_INFO"   : @(RPRLogLevelInfo),
        @"LOGLEVEL_WARN"   : @(RPRLogLevelWarn),
        @"LOGLEVEL_ERROR"  : @(RPRLogLevelError),
        @"LOGLEVEL_NONE"   : @(RPRLogLevelNone),

        @"GENDER_OTHER"    : @(RPRUserProfileGenderOther),
        @"GENDER_MALE"     : @(RPRUserProfileGenderMale),
        @"GENDER_FEMALE"   : @(RPRUserProfileGenderFemale),

        @"REMOTE_CONFIG_SUCCESS"            : @(RPRRemoteConfigFetchStatusSuccess),
        @"REMOTE_CONFIG_TIMEOUT_REACHED"    : @(RPRRemoteConfigFetchStatusTimeoutReached),
        @"REMOTE_CONFIG_ALREADY_FETCHED"    : @(RPRRemoteConfigFetchStatusAlreadyFetched),

        @"CAMPAIGN_TYPE_UNKNOWN"            : @(RPRCampaignTypeUnknown),
        @"CAMPAIGN_TYPE_PUSH_NOTIFICATION"  : @(RPRCampaignTypePushNotification),
        @"CAMPAIGN_TYPE_IN_APP_MESSAGE"     : @(RPRCampaignTypeInAppMessage),
        @"CAMPAIGN_TYPE_WEB_MESSAGE"        : @(RPRCampaignTypeWebMessage),
        @"CAMPAIGN_TYPE_ALL"        : @(RPRCampaignTypeAll),

        @"PREFECTURE_HOKKAIDO" : @(RPRUserProfilePrefectureHokkaido),
        @"PREFECTURE_AOMORI" : @(RPRUserProfilePrefectureAomori),
        @"PREFECTURE_IWATE" : @(RPRUserProfilePrefectureIwate),
        @"PREFECTURE_MIYAGI" : @(RPRUserProfilePrefectureMiyagi),
        @"PREFECTURE_AKITA" : @(RPRUserProfilePrefectureAkita),
        @"PREFECTURE_YAMAGATA" : @(RPRUserProfilePrefectureYamagata),
        @"PREFECTURE_FUKUSHIMA" : @(RPRUserProfilePrefectureFukushima),
        @"PREFECTURE_IBARAKI" : @(RPRUserProfilePrefectureIbaraki),
        @"PREFECTURE_TOCHIGI" : @(RPRUserProfilePrefectureTochigi),
        @"PREFECTURE_GUNMA" : @(RPRUserProfilePrefectureGunma),
        @"PREFECTURE_SAITAMA" : @(RPRUserProfilePrefectureSaitama),
        @"PREFECTURE_CHIBA" : @(RPRUserProfilePrefectureChiba),
        @"PREFECTURE_TOKYO" : @(RPRUserProfilePrefectureTokyo),
        @"PREFECTURE_KANAGAWA" : @(RPRUserProfilePrefectureKanagawa),
        @"PREFECTURE_NIIGATA" : @(RPRUserProfilePrefectureNiigata),
        @"PREFECTURE_TOYAMA" : @(RPRUserProfilePrefectureToyama),
        @"PREFECTURE_ISHIKAWA" : @(RPRUserProfilePrefectureIshikawa),
        @"PREFECTURE_FUKUI" : @(RPRUserProfilePrefectureFukui),
        @"PREFECTURE_YAMANASHI" : @(RPRUserProfilePrefectureYamanashi),
        @"PREFECTURE_NAGANO" : @(RPRUserProfilePrefectureNagano),
        @"PREFECTURE_GIFU" : @(RPRUserProfilePrefectureGifu),
        @"PREFECTURE_SHIZUOKA" : @(RPRUserProfilePrefectureShizuoka),
        @"PREFECTURE_AICHI" : @(RPRUserProfilePrefectureAichi),
        @"PREFECTURE_MIE" : @(RPRUserProfilePrefectureMie),
        @"PREFECTURE_SHIGA" : @(RPRUserProfilePrefectureShiga),
        @"PREFECTURE_KYOTO" : @(RPRUserProfilePrefectureKyoto),
        @"PREFECTURE_OSAKA" : @(RPRUserProfilePrefectureOsaka),
        @"PREFECTURE_HYOGO" : @(RPRUserProfilePrefectureHyogo),
        @"PREFECTURE_NARA" : @(RPRUserProfilePrefectureNara),
        @"PREFECTURE_WAKAYAMA" : @(RPRUserProfilePrefectureWakayama),
        @"PREFECTURE_TOTTORI" : @(RPRUserProfilePrefectureTottori),
        @"PREFECTURE_SHIMANE" : @(RPRUserProfilePrefectureShimane),
        @"PREFECTURE_OKAYAMA" : @(RPRUserProfilePrefectureOkayama),
        @"PREFECTURE_HIROSHIMA" : @(RPRUserProfilePrefectureHiroshima),
        @"PREFECTURE_YAMAGUCHI" : @(RPRUserProfilePrefectureYamaguchi),
        @"PREFECTURE_TOKUSHIMA" : @(RPRUserProfilePrefectureTokushima),
        @"PREFECTURE_KAGAWA" : @(RPRUserProfilePrefectureKagawa),
        @"PREFECTURE_EHIME" : @(RPRUserProfilePrefectureEhime),
        @"PREFECTURE_KOCHI" : @(RPRUserProfilePrefectureKochi),
        @"PREFECTURE_FUKUOKA" : @(RPRUserProfilePrefectureFukuoka),
        @"PREFECTURE_SAGA" : @(RPRUserProfilePrefectureSaga),
        @"PREFECTURE_NAGASAKI" : @(RPRUserProfilePrefectureNagasaki),
        @"PREFECTURE_KUMAMOTO" : @(RPRUserProfilePrefectureKumamoto),
        @"PREFECTURE_OITA" : @(RPRUserProfilePrefectureOita),
        @"PREFECTURE_MIYAZAKI" : @(RPRUserProfilePrefectureMiyazaki),
        @"PREFECTURE_KAGOSHIMA" : @(RPRUserProfilePrefectureKagoshima),
        @"PREFECTURE_OKINAWA" : @(RPRUserProfilePrefectureOkinawa)
    };
};

- (NSDictionary *)getConstants
{
  return [self constantsToExport];
}

+ (BOOL)requiresMainQueueSetup
{
    return YES;  // needed because we override `constantsToExport`
}


#ifdef RCT_NEW_ARCH_ENABLED

// Opt In / Opt Out

- (void)optIn:(BOOL)endUserOptedIn
{
    [_reproImpl optIn:endUserOptedIn];
}

// User profile

- (void)setUserID:(NSString *)userID
{
    [_reproImpl setUserID:userID];
}

- (void)getUserID:(RCTResponseSenderBlock)callback
{
    [_reproImpl getUserID:callback];
}

- (void)getDeviceID:(RCTResponseSenderBlock)callback
{
    [_reproImpl getDeviceID:callback];
}

- (void)setStringUserProfile:(NSString *)key value:(NSString *)value
{
    [_reproImpl setStringUserProfile:key value:value];
}

- (void)setIntUserProfile:(NSString *)key value:(double)value
{
    [_reproImpl setIntUserProfile:key value:(NSInteger)value];
}

- (void)setDoubleUserProfile:(NSString *)key value:(double)value
{
    [_reproImpl setDoubleUserProfile:key value:value];
}

- (void)setDateUserProfile:(NSString *)key value:(NSString *)value
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
    [formatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
    NSDate *date = [formatter dateFromString:value];

    [_reproImpl setDateUserProfile:key value:date];
}

- (void)setUserGender:(double)value
{
    NSInteger intValue = (NSInteger)value;
    [_reproImpl setUserGender:(RPRUserProfileGender)intValue];
}

- (void)setUserEmailAddress:(NSString *)value
{
    [_reproImpl setUserEmailAddress:value];
}

- (void)setUserResidencePrefecture:(double)value
{
    NSInteger intValue = (NSInteger)value;
    [_reproImpl setUserResidencePrefecture:(RPRUserProfilePrefecture)intValue];
}

- (void)setUserDateOfBirth:(NSString *)value
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
    [formatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
    NSDate *date = [formatter dateFromString:value];

    [_reproImpl setUserDateOfBirth:date];
}

- (void)setUserAge:(double)value
{
    [_reproImpl setUserAge:(NSInteger)value];
}

- (void)onlySetIfAbsentStringUserProfile:(NSString *)key value:(NSString *)value
{
    [_reproImpl onlySetIfAbsentStringUserProfile:key value:value];
}

- (void)onlySetIfAbsentIntUserProfile:(NSString *)key value:(double)value
{
    [_reproImpl onlySetIfAbsentIntUserProfile:key value:(NSInteger)value];
}

- (void)onlySetIfAbsentDoubleUserProfile:(NSString *)key value:(double)value
{
    [_reproImpl onlySetIfAbsentDoubleUserProfile:key value:value];
}

- (void)onlySetIfAbsentDateUserProfile:(NSString *)key value:(NSString *)value
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
    [formatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
    NSDate *date = [formatter dateFromString:value];

    [_reproImpl onlySetIfAbsentDateUserProfile:key value:date];
}

- (void)incrementIntUserProfileBy:(NSString *)key value:(double)value
{
    [_reproImpl incrementIntUserProfileBy:key value:(NSInteger)value];
}

- (void)decrementIntUserProfileBy:(NSString *)key value:(double)value
{
    [_reproImpl decrementIntUserProfileBy:key value:(NSInteger)value];
}

- (void)incrementDoubleUserProfileBy:(NSString *)key value:(double)value
{
    [_reproImpl incrementDoubleUserProfileBy:key value:value];
}

- (void)decrementDoubleUserProfileBy:(NSString *)key value:(double)value
{
    [_reproImpl decrementDoubleUserProfileBy:key value:value];
}

- (void)onlySetIfAbsentUserGender:(double)value
{
    NSInteger intValue = (NSInteger)value;
    [_reproImpl onlySetIfAbsentUserGender:(RPRUserProfileGender)value];
}

- (void)onlySetIfAbsentUserEmailAddress:(NSString *)value
{
    [_reproImpl onlySetIfAbsentUserEmailAddress:value];
}

- (void)onlySetIfAbsentUserResidencePrefecture:(double)value
{
    NSInteger intValue = (NSInteger)value;
    [_reproImpl onlySetIfAbsentUserResidencePrefecture:(RPRUserProfilePrefecture)intValue];
}

- (void)onlySetIfAbsentUserDateOfBirth:(NSString *)value
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
    [formatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
    NSDate *date = [formatter dateFromString:value];

    [_reproImpl onlySetIfAbsentUserDateOfBirth:date];
}

- (void)onlySetIfAbsentUserAge:(double)value
{
    [_reproImpl onlySetIfAbsentUserAge:(NSInteger)value];
}

- (void)incrementUserAgeBy:(double)value
{
    [_reproImpl incrementUserAgeBy:(NSInteger)value];
}

- (void)decrementUserAgeBy:(double)value
{
    [_reproImpl decrementUserAgeBy:(NSInteger)value];
}

- (void)deleteUserProfile:(NSString *)key
{
    [_reproImpl deleteUserProfile:key];
}

- (void)deleteUserGender
{
    [_reproImpl deleteUserGender];
}

- (void)deleteUserEmailAddress
{
    [_reproImpl deleteUserEmailAddress];
}

- (void)deleteUserResidencePrefecture
{
    [_reproImpl deleteUserResidencePrefecture];
}

- (void)deleteUserDateOfBirth
{
    [_reproImpl deleteUserDateOfBirth];
}

- (void)deleteUserAge
{
    [_reproImpl deleteUserAge];
}

// Custom event tracking

- (void)track:(NSString *)eventName properties:(NSDictionary *)props
{
    [_reproImpl track:eventName properties:props];
}



// Standard event tracking

- (void)trackViewContent:(NSString *)contentId props:(NSDictionary *)props
{
    [_reproImpl trackViewContent:contentId properties:props];
}

- (void)trackSearch:(NSDictionary *)props
{
    [_reproImpl trackSearch:props];
}

- (void)trackAddToCart:(NSString *)contentId props:(NSDictionary *)props
{
    [_reproImpl trackAddToCart:contentId properties:props];
}

- (void)trackAddToWishlist:(NSDictionary *)props
{
    [_reproImpl trackAddToWishlist:props];
}

- (void)trackInitiateCheckout:(NSDictionary *)props
{
    [_reproImpl trackInitiateCheckout:props];
}

- (void)trackAddPaymentInfo:(NSDictionary *)props
{
    [_reproImpl trackAddPaymentInfo:props];
}

- (void)trackPurchase:(NSString *)contentId value:(double)value currency:(NSString *)currency props:(NSDictionary *)props
{
    [_reproImpl trackPurchase:contentId value:value currency:currency properties:props];
}

- (void)trackShare:(NSDictionary *)props
{
    [_reproImpl trackShare:props];
}

- (void)trackLead:(NSDictionary *)props
{
    [_reproImpl trackLead:props];
}

- (void)trackCompleteRegistration:(NSDictionary *)props
{
    [_reproImpl trackCompleteRegistration:props];
}

- (void)trackNotificationOpened:(NSString *)notificationId
{
    [_reproImpl trackNotificationOpened:notificationId];
}

// Other

- (void)setLogLevel:(double)level
{
    NSInteger intLevel = (NSInteger)level;
    [_reproImpl setLogLevel:(RPRLogLevel)intLevel];
}

- (void)setPushDeviceTokenString:(NSString *)deviceTokenHexString
{
    [_reproImpl setPushDeviceTokenString:deviceTokenHexString];
}

- (void)setPushRegistrationID:(NSString *)pushRegId
{
    [_reproImpl setPushDeviceTokenString:pushRegId];
}

- (void)setPushToken:(NSString *)token
{
    [_reproImpl setPushDeviceTokenString:token];
}

- (void)enablePushNotification
{
    [_reproImpl enablePushNotification];
}

// NOTE: Should better be called native from AppDelegate::didFinishLaunchingWithOptions
- (void)setup:(NSString *)token
{
    [_reproImpl setup:token];
}

- (void)enableInAppMessagesOnForegroundTransition
{
    [_reproImpl enableInAppMessagesOnForegroundTransition];
}

// NOTE: Should better be called native from AppDelegate::didFinishLaunchingWithOptions if needed
- (void)disableInAppMessagesOnForegroundTransition
{
    [_reproImpl disableInAppMessagesOnForegroundTransition];
}

- (void)getNewsFeeds:(double)limit callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl getNewsFeeds:limit campaignType:@(RPRCampaignTypePushNotification) callback:callback];
}

- (void)oldArchGetNewsFeeds:(double)limit campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback
{
    // Only Legacy Architecture method
}

- (void)getNewsFeedsFor:(double)limit offsetID:(double)offsetID callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl getNewsFeedsFor:limit offsetID:offsetID campaignType:@(RPRCampaignTypePushNotification) callback:callback];
}

- (void)oldArchGetNewsFeedsFor:(double)limit offsetID:(double)offsetID campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback
{
    // Only Legacy Architecture method
}

- (void)getNewsFeedsWithCampaignType:(double)limit campaignType:(double)type callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl getNewsFeeds:limit campaignType:@(type) callback:callback];
}

- (void)getNewsFeedsWithCampaignTypeFor:(double)limit offsetID:(double)offsetID campaignType:(double)type callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl getNewsFeedsFor:limit offsetID:offsetID campaignType:@(type) callback:callback];
}

- (void)updateNewsFeeds:(NSArray<NSDictionary *> *)entryJsons callback:(RCTResponseSenderBlock)callback
{
    [_reproImpl updateNewsFeeds:entryJsons callback:callback];
}

- (void)oldArchUpdateNewsFeeds:(NSArray<NSDictionary *> *)entryJsons callback:(RCTResponseSenderBlock)callback
{
    // Only Legacy Architecture method
}

- (void)setSilverEggProdKey:(NSString *)silverEggProdKey
{
    [_reproImpl setSilverEggProdKey:silverEggProdKey];
}

- (void)setSilverEggCookie:(NSString *)silverEggCookie
{
    [_reproImpl setSilverEggCookie:silverEggCookie];
}

- (void)linkLineID:(NSString *)lineUserId lineChannelId:(NSString *)lineChannelId
{
    [_reproImpl linkLineID:lineUserId lineChannelID:lineChannelId];
}

- (void)unlinkLineID:(NSString *)lineUserId lineChannelId:(NSString *)lineChannelId
{
    [_reproImpl unlinkLineID:lineUserId lineChannelID:lineChannelId];
}


- (void)_handleWebViewUrl:(NSString *)webViewRequestUrl
{
    [_reproImpl _webviewJavaScriptOpenUrlHandler:webViewRequestUrl];
}

#else

// Opt In / Opt Out

RCT_EXPORT_METHOD(optIn:(BOOL)endUserOptedIn)
{
    [_reproImpl optIn:endUserOptedIn];
}

// User profile

RCT_EXPORT_METHOD(setUserID:(NSString *)userID)
{
    [_reproImpl setUserID:userID];
}

RCT_EXPORT_METHOD(getUserID:(RCTResponseSenderBlock)callback)
{
    [_reproImpl getUserID:callback];
}

RCT_EXPORT_METHOD(getDeviceID:(RCTResponseSenderBlock)callback)
{
    [_reproImpl getDeviceID:callback];
}

RCT_EXPORT_METHOD(setStringUserProfile:(NSString *)key value:(NSString *)value)
{
    [_reproImpl setStringUserProfile:key value:value];
}

RCT_EXPORT_METHOD(setIntUserProfile:(NSString *)key value:(NSInteger)value)
{
    [_reproImpl setIntUserProfile:key value:value];
}

RCT_EXPORT_METHOD(setDoubleUserProfile:(NSString *)key value:(double)value)
{
    [_reproImpl setDoubleUserProfile:key value:value];
}

RCT_EXPORT_METHOD(setDateUserProfile:(NSString *)key value:(NSDate *)value)
{
    [_reproImpl setDateUserProfile:key value:value];
}

RCT_EXPORT_METHOD(setUserGender:(NSInteger)value)
{
    [_reproImpl setUserGender:value];
}

RCT_EXPORT_METHOD(setUserEmailAddress:(NSString *)value)
{
    [_reproImpl setUserEmailAddress:value];
}

RCT_EXPORT_METHOD(setUserResidencePrefecture:(NSInteger)value)
{
    [_reproImpl setUserResidencePrefecture:value];
}

RCT_EXPORT_METHOD(setUserDateOfBirth:(NSDate *)value)
{
    [_reproImpl setUserDateOfBirth:value];
}

RCT_EXPORT_METHOD(setUserAge:(NSInteger)value)
{
    [_reproImpl setUserAge:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentStringUserProfile:(NSString *)key value:(NSString *)value)
{
    [_reproImpl onlySetIfAbsentStringUserProfile:key value:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentIntUserProfile:(NSString *)key value:(NSInteger)value)
{
    [_reproImpl onlySetIfAbsentIntUserProfile:key value:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentDoubleUserProfile:(NSString *)key value:(NSInteger)value)
{
    [_reproImpl onlySetIfAbsentDoubleUserProfile:key value:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentDateUserProfile:(NSString *)key value:(NSDate *)value)
{
    [_reproImpl onlySetIfAbsentDateUserProfile:key value:value];
}

RCT_EXPORT_METHOD(incrementIntUserProfileBy:(NSString *)key value:(NSInteger)value)
{
    [_reproImpl incrementIntUserProfileBy:key value:value];
}

RCT_EXPORT_METHOD(decrementIntUserProfileBy:(NSString *)key value:(NSInteger)value)
{
    [_reproImpl decrementIntUserProfileBy:key value:value];
}

RCT_EXPORT_METHOD(incrementDoubleUserProfileBy:(NSString *)key value:(double)value)
{
    [_reproImpl incrementDoubleUserProfileBy:key value:value];
}

RCT_EXPORT_METHOD(decrementDoubleUserProfileBy:(NSString *)key value:(double)value)
{
    [_reproImpl decrementDoubleUserProfileBy:key value:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentUserGender:(RPRUserProfileGender)value)
{
    [_reproImpl onlySetIfAbsentUserGender:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentUserEmailAddress:(NSString *)value)
{
    [_reproImpl onlySetIfAbsentUserEmailAddress:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentUserResidencePrefecture:(RPRUserProfilePrefecture)value)
{
    [_reproImpl onlySetIfAbsentUserResidencePrefecture:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentUserDateOfBirth:(NSDate *)value)
{
    [_reproImpl onlySetIfAbsentUserDateOfBirth:value];
}

RCT_EXPORT_METHOD(onlySetIfAbsentUserAge:(NSInteger)value)
{
    [_reproImpl onlySetIfAbsentUserAge:value];
}

RCT_EXPORT_METHOD(incrementUserAgeBy:(NSInteger)value)
{
    [_reproImpl incrementUserAgeBy:value];
}

RCT_EXPORT_METHOD(decrementUserAgeBy:(NSInteger)value)
{
    [_reproImpl decrementUserAgeBy:value];
}

RCT_EXPORT_METHOD(deleteUserProfile:(NSString *)key)
{
    [_reproImpl deleteUserProfile:key];
}

RCT_EXPORT_METHOD(deleteUserGender)
{
    [_reproImpl deleteUserGender];
}

RCT_EXPORT_METHOD(deleteUserEmailAddress)
{
    [_reproImpl deleteUserEmailAddress];
}

RCT_EXPORT_METHOD(deleteUserResidencePrefecture)
{
    [_reproImpl deleteUserResidencePrefecture];
}

RCT_EXPORT_METHOD(deleteUserDateOfBirth)
{
    [_reproImpl deleteUserDateOfBirth];
}

RCT_EXPORT_METHOD(deleteUserAge)
{
    [_reproImpl deleteUserAge];
}

// Custom event tracking

RCT_EXPORT_METHOD(track:(NSString *)eventName properties:(NSDictionary *)props)
{
    [_reproImpl track:eventName properties:props];
}

// Standard event tracking

RCT_EXPORT_METHOD(trackViewContent:(NSString *)contentID properties:(NSDictionary *)props)
{
    [_reproImpl trackViewContent:contentID properties:props];
}

RCT_EXPORT_METHOD(trackSearch:(NSDictionary *)props)
{
    [_reproImpl trackSearch:props];
}

RCT_EXPORT_METHOD(trackAddToCart:(NSString *)contentID properties:(NSDictionary *)props)
{
    [_reproImpl trackAddToCart:contentID properties:props];
}

RCT_EXPORT_METHOD(trackAddToWishlist:(NSDictionary *)props)
{
    [_reproImpl trackAddToWishlist:props];
}

RCT_EXPORT_METHOD(trackInitiateCheckout:(NSDictionary *)props)
{
    [_reproImpl trackInitiateCheckout:props];
}

RCT_EXPORT_METHOD(trackAddPaymentInfo:(NSDictionary *)props)
{
    [_reproImpl trackAddPaymentInfo:props];
}

RCT_EXPORT_METHOD(trackPurchase:(NSString *)contentID value:(double)value currency:(NSString *)currency properties:(NSDictionary *)props)
{
    [_reproImpl trackPurchase:contentID value:value currency:currency properties:props];
}

RCT_EXPORT_METHOD(trackShare:(NSDictionary *)props)
{
    [_reproImpl trackShare:props];
}

RCT_EXPORT_METHOD(trackLead:(NSDictionary *)props)
{
    [_reproImpl trackLead:props];
}

RCT_EXPORT_METHOD(trackCompleteRegistration:(NSDictionary *)props)
{
    [_reproImpl trackCompleteRegistration:props];
}

RCT_EXPORT_METHOD(trackNotificationOpened:(NSString *)notificationId)
{
    [_reproImpl trackNotificationOpened:notificationId];
}

// Other

RCT_EXPORT_METHOD(setLogLevel:(RPRLogLevel)level)
{
    [_reproImpl setLogLevel:level];
}

RCT_EXPORT_METHOD(setPushDeviceTokenString:(NSString *)deviceTokenHexString)
{
    [_reproImpl setPushDeviceTokenString:deviceTokenHexString];
}

RCT_EXPORT_METHOD(setPushRegistrationID:(NSString *)pushRegId)
{
    [_reproImpl setPushDeviceTokenString:pushRegId];
}

RCT_EXPORT_METHOD(setPushToken:(NSString *)token)
{
    [_reproImpl setPushDeviceTokenString:token];
}

RCT_EXPORT_METHOD(enablePushNotification)
{
    [_reproImpl enablePushNotification];
}

// NOTE: Should better be called native from AppDelegate::didFinishLaunchingWithOptions
RCT_EXPORT_METHOD(setup:(NSString *)token)
{
    [_reproImpl setup:token];
}

RCT_EXPORT_METHOD(enableInAppMessagesOnForegroundTransition)
{
    [_reproImpl enableInAppMessagesOnForegroundTransition];
}

// NOTE: Should better be called native from AppDelegate::didFinishLaunchingWithOptions if needed
RCT_EXPORT_METHOD(disableInAppMessagesOnForegroundTransition)
{
    [_reproImpl disableInAppMessagesOnForegroundTransition];
}

RCT_EXPORT_METHOD(getNewsFeeds:(double)limit callback:(RCTResponseSenderBlock)callback)
{
    // Only New Architecture method
}

RCT_EXPORT_METHOD(oldArchGetNewsFeeds:(uint64_t)limit campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback)
{
    NSError *error = nil;
    RPRCampaignType campaignType = RPRCampaignTypeUnknown;

    if (type) {
        if ([type isEqualToNumber:@(RPRCampaignTypePushNotification)]) {
            campaignType = RPRCampaignTypePushNotification;
        } else if ([type isEqualToNumber:@(RPRCampaignTypeInAppMessage)]) {
            campaignType = RPRCampaignTypeInAppMessage;
        } else if ([type isEqualToNumber:@(RPRCampaignTypeWebMessage)]) {
            campaignType = RPRCampaignTypeWebMessage;
        } else if ([type isEqualToNumber:@(RPRCampaignTypeAll)]) {
            campaignType = RPRCampaignTypeAll;
        }
    }

    NSArray<RPRNewsFeedEntry *> * entries = [Repro getNewsFeeds:limit campaignType:campaignType error:&error];

    if (error) {
        NSString *errString = [error localizedDescription];
        callback(@[@{ @"message": errString }, [NSNull null]]);
        return;
    }

    NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZZZ";
    formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
    formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    formatter.calendar = [NSCalendar.alloc initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

    NSMutableArray *entryJsons = [NSMutableArray.alloc initWithCapacity:entries.count];

    for (RPRNewsFeedEntry *entry in entries) {

        NSString *formattedDateString = [formatter stringFromDate:entry.deliveredAt];

        NSDictionary *entryJson = @{
            @"newsfeed_id": @(entry.ID),
            @"device_id": entry.deviceID,
            @"title": entry.title,
            @"summary": entry.summary,
            @"body": entry.body,
            @"campaign_type": @(entry.campaignType),
            @"shown": @(entry.shown),
            @"read": @(entry.read),
            @"delivered_at": formattedDateString,
            @"link_url": entry.linkUrl ? [entry.linkUrl absoluteString] : @"",
            @"link_url_string": entry.linkUrlString,
            @"image_url": entry.imageUrl ? [entry.imageUrl absoluteString] : @"",
            @"image_url_string": entry.imageUrlString,
        };

        [entryJsons addObject:entryJson];
    }

    callback(@[[NSNull null], safe_value(entryJsons)]);
}

RCT_EXPORT_METHOD(getNewsFeedsFor:(double)limit offsetID:(double)offsetID campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback)
{
    // Only New Architecture method
}

RCT_EXPORT_METHOD(oldArchGetNewsFeedsFor:(uint64_t)limit offsetID:(uint64_t)offsetID campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback)
{
    NSError *error = nil;
    RPRCampaignType campaignType = RPRCampaignTypeUnknown;

    if (type) {
        if ([type isEqualToNumber:@(RPRCampaignTypePushNotification)]) {
            campaignType = RPRCampaignTypePushNotification;
        } else if ([type isEqualToNumber:@(RPRCampaignTypeInAppMessage)]) {
            campaignType = RPRCampaignTypeInAppMessage;
        } else if ([type isEqualToNumber:@(RPRCampaignTypeWebMessage)]) {
            campaignType = RPRCampaignTypeWebMessage;
        } else if ([type isEqualToNumber:@(RPRCampaignTypeAll)]) {
            campaignType = RPRCampaignTypeAll;
        }
    }

    NSArray<RPRNewsFeedEntry *> *entries = [Repro getNewsFeeds:limit offsetID:offsetID campaignType:campaignType error:&error];

    if (error) {
        NSString *errString = [error localizedDescription];
        callback(@[@{ @"message": errString }, [NSNull null]]);
        return;
    }

    NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZZZ";
    formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
    formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    formatter.calendar = [NSCalendar.alloc initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

    NSMutableArray *entryJsons = [NSMutableArray.alloc initWithCapacity:entries.count];

    for (RPRNewsFeedEntry *entry in entries) {

        NSString *formattedDateString = [formatter stringFromDate:entry.deliveredAt];

        NSDictionary *entryJson = @{
            @"newsfeed_id": @(entry.ID),
            @"device_id": entry.deviceID,
            @"title": entry.title,
            @"summary": entry.summary,
            @"body": entry.body,
            @"campaign_type": @(entry.campaignType),
            @"shown": @(entry.shown),
            @"read": @(entry.read),
            @"delivered_at": formattedDateString,
            @"link_url": entry.linkUrl ? [entry.linkUrl absoluteString] : @"",
            @"link_url_string": entry.linkUrlString,
            @"image_url": entry.imageUrl ? [entry.imageUrl absoluteString] : @"",
            @"image_url_string": entry.imageUrlString,
        };

        [entryJsons addObject:entryJson];
    }

    callback(@[[NSNull null], safe_value(entryJsons)]);
}

RCT_EXPORT_METHOD(getNewsFeedsWithCampaignType:(double)limit campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback)
{
    // Only New Architecture method
}

RCT_EXPORT_METHOD(getNewsFeedsWithCampaignTypeFor:(double)limit offsetID:(double)offsetID campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback)
{
    // Only New Architecture method
}

RCT_EXPORT_METHOD(updateNewsFeeds:(NSArray<NSDictionary *> *)entryJsons callback:(RCTResponseSenderBlock)callback)
{
    // Only New Architecture method
}

RCT_EXPORT_METHOD(oldArchUpdateNewsFeeds:(NSArray<NSDictionary *> *)entryJsons callback:(RCTResponseSenderBlock)callback)
{
    NSMutableArray<RPRNewsFeedEntry *> *entries = [NSMutableArray.alloc initWithCapacity:entryJsons.count];

    for (NSDictionary *entryJson in entryJsons) {
        RPRNewsFeedEntry *entry = [RPRNewsFeedEntry.alloc initWithDictionary: entryJson];
        [entries addObject:entry];
    }

    NSError *error = nil;
    [Repro updateNewsFeeds:entries error:&error];

    if (error) {
        NSString *errString = [error localizedDescription];
        callback(@[@{ @"message": errString }]);
        return;
    }

    callback(@[[NSNull null]]);
}

RCT_EXPORT_METHOD(setSilverEggProdKey:(NSString *)silverEggProdKey)
{
    [_reproImpl setSilverEggProdKey:silverEggProdKey];
}

RCT_EXPORT_METHOD(setSilverEggCookie:(NSString *)silverEggCookie)
{
    [_reproImpl setSilverEggCookie:silverEggCookie];
}

RCT_EXPORT_METHOD(linkLineID:(NSString *)lineUserId lineChannelId:(NSString *)lineChannelId)
{
    [_reproImpl linkLineID:lineUserId lineChannelID:lineChannelId];
}

RCT_EXPORT_METHOD(unlinkLineID:(NSString *)lineUserId lineChannelId:(NSString *)lineChannelId)
{
    [_reproImpl unlinkLineID:lineUserId lineChannelID:lineChannelId];
}

RCT_EXPORT_METHOD(_handleWebViewUrl:(NSString *)webViewRequestUrl)
{
    [_reproImpl _webviewJavaScriptOpenUrlHandler:webViewRequestUrl];
}

#endif

#if RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
    return std::make_shared<facebook::react::NativeReproReactBridgeSpecJSI>(params);
}
#endif

@end



@implementation RPREventEmitterOpenUrl

RCT_EXPORT_MODULE(ReproEventEmitterOpenUrl)

- (NSArray<NSString*> *)supportedEvents
{
    return @[@"__RPR__openUrlCallback"];
}

- (void)startObserving
{
    [Repro setOpenUrlCallback:^(NSURL * _Nonnull url) {
        [self sendEventWithName:@"__RPR__openUrlCallback" body:url.absoluteString];
    }];
}

- (void)stopObserving
{
    [Repro setOpenUrlCallback:nil];
}

#if RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params
{
    return std::make_shared<facebook::react::NativeReproEventEmitterOpenUrlSpecJSI>(params);
}
#endif

@end


