//
//  RPRReproReactBridgeImpl.m
//  RPRReproReactBridgeImpl
//
//  Created by Koki Oshima on 2025/07/16.
//  Copyright © 2025 Repro Inc. All rights reserved.
//


#import "RPRReproReactBridgeImpl.h"
#import <Repro/Repro.h>
#import <Repro/RPRRemoteConfig.h>
#import <Repro/RPRNewsFeedEntry.h>
#import <Repro/RPRUserProfileTypes.h>
#import <React/RCTLog.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

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

@interface Repro (NonPublicApi)
+ (BOOL)_webviewJavaScriptOpenUrlHandler:(NSString *)url;
@end

@implementation RPRReproReactBridgeImpl

// Remote Config
- (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];
}

/// You may not need this method because the default behavior is:
///    - After a call to `Repro.setup()`, automatically fetch every time the app will enter foreground
///    - Run `activateFetched` as soon as a response was received.
///
/// If you need a completionHandler to ensure the remoteConfig gets activated at a certain point in time
/// or want to validate remote config functionality while development, you should use this method. You can
/// only set one completionHandler at a time. Also only one fetch per app foreground/background cycle is
/// permitted. Therefore you should call this when your app comes to foreground, preferably
/// from `applicationWillEnterForeground`.
///
/// If the completionHandler handler is called with status `RPRRemoteConfigFetchStatusSuccess`, you should
/// proceed with calling `activateFetched` in the completionHandler or after the completionHandler has
/// been executed.
///
/// After `activateFetched` has been called, new remote config values are available. This completionHandler
/// is always guaranteed to be called on the main thread. The callback will be invalidated and not executed
/// if the app goes to background or the end-user OptsOut via the OptIn/OptOut API.
- (void)fetch:(double)timeout completionHandler:(RCTResponseSenderBlock)callback
{
    double timeoutSecs = timeout * 0.001;
    [[Repro remoteConfig] fetchWithTimeout:timeoutSecs completionHandler:^(RPRRemoteConfigFetchStatus status) {
        callback(@[@(status)]);
    }];
}

/// This is only needed if you use `fetchWithTimeout:completionHandler:`. See above.
/// Returns YES if a previously fetched remote config has replaced the current remote config.
- (void)activateFetched
{
    [[Repro remoteConfig] activateFetched];
}

/// Set local defaults for remote config queries via dictionary.
- (void)setDefaultsFromDictionary:(NSDictionary<NSString *, id> *) json
{
    [[Repro remoteConfig] setDefaultsFromDictionary: json];
}

/// Set local defaults for remote config queries via a json string.
- (void)setDefaultsFromJsonString:(NSString *)string
{
    [[Repro remoteConfig] setDefaultsFromJsonString: string];
}

/// Access to remote config values.
- (void)getValue:(NSString*)key callback:(RCTResponseSenderBlock)callback
{
    callback(@[safe_value([[[Repro remoteConfig] valueForKey: key] stringValue])]);
}

/// Return a dictonary with all key value pairs.
- (void)getAllValues:(RCTResponseSenderBlock)callback
{
    callback(@[safe_value([self toDictionary: [[Repro remoteConfig] allValues]])]);
}

/// Return a dictonary with all key value pairs for a given prefix. Pass `nil` or an empty string to get all values.
- (void)getAllValuesWithPrefix:(NSString*)key callback:(RCTResponseSenderBlock)callback
{
    callback(@[safe_value([self toDictionary:[[Repro remoteConfig] allValuesWithPrefix: key]])]);
}

/// Returns the local default value for a key.
- (void)getLocalDefaultValue:(NSString*)key callback:(RCTResponseSenderBlock)callback
{
    callback(@[safe_value([[[Repro remoteConfig] localDefaultValueForKey: key] stringValue])]);
}

/// Reset all data. Local config & remote Config. Should only be used while in development.
- (void)forceReset
{
    [[Repro remoteConfig] forceReset];
}

// Repro
// Opt In / Opt Out

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

// User profile

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

- (void)getUserID:(RCTResponseSenderBlock)callback
{
    callback(@[[NSNull null], safe_value([Repro getUserID])]);
}

- (void)getDeviceID:(RCTResponseSenderBlock)callback
{
    callback(@[[NSNull null], safe_value([Repro getDeviceID])]);
}

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

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

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

- (void)setDateUserProfile:(NSString *)key value:(NSDate *)value
{
    [Repro setDateUserProfile:value forKey:key];
}

- (void)setUserGender:(RPRUserProfileGender)value
{
    [Repro setUserGender:value];
}

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

- (void)setUserResidencePrefecture:(RPRUserProfilePrefecture)value
{
    [Repro setUserResidencePrefecture:value];
}

- (void)setUserDateOfBirth:(NSDate *)value
{
    [Repro setUserDateOfBirth:value];
}

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

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

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

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

- (void)onlySetIfAbsentDateUserProfile:(NSString *)key value:(NSDate *)value
{
    [Repro onlySetIfAbsentDateUserProfile:value forKey:key];
}

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

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

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

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

- (void)onlySetIfAbsentUserGender:(RPRUserProfileGender)value
{
    [Repro onlySetIfAbsentUserGender:value];
}

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

- (void)onlySetIfAbsentUserResidencePrefecture:(RPRUserProfilePrefecture)value
{
    [Repro onlySetIfAbsentUserResidencePrefecture:value];
}

- (void)onlySetIfAbsentUserDateOfBirth:(NSDate *)value
{
    [Repro onlySetIfAbsentUserDateOfBirth:value];
}

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

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

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

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

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

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

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

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

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

// Custom event tracking

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

// Standard event tracking

- (void)trackViewContent:(NSString *)contentID properties:(NSDictionary *)props
{
    RPRViewContentProperties *properties = [[RPRViewContentProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackViewContent:contentID properties:properties];
}

- (void)trackSearch:(NSDictionary *)props
{
    RPRSearchProperties *properties = [[RPRSearchProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_id"]))        { properties.contentID        = [RCTConvert NSString:val];  }
    if ((val = props[@"search_string"]))     { properties.searchString     = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackSearch:properties];
}



- (void)trackAddToCart:(NSString *)contentID properties:(NSDictionary *)props
{
    RPRAddToCartProperties *properties = [[RPRAddToCartProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackAddToCart:contentID properties:properties];
}


- (void)trackAddToWishlist:(NSDictionary *)props
{
    RPRAddToWishlistProperties *properties = [[RPRAddToWishlistProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_id"]))        { properties.contentID        = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackAddToWishlist:properties];
}

- (void)trackInitiateCheckout:(NSDictionary *)props
{
    RPRInitiateCheckoutProperties *properties = [[RPRInitiateCheckoutProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_id"]))        { properties.contentID        = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"num_items"]))         { properties.numItems         = [RCTConvert NSInteger:val]; }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackInitiateCheckout:properties];
}

- (void)trackAddPaymentInfo:(NSDictionary *)props
{
    RPRAddPaymentInfoProperties *properties = [[RPRAddPaymentInfoProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_id"]))        { properties.contentID        = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackAddPaymentInfo:properties];
}

- (void)trackPurchase:(NSString *)contentID value:(double)value currency:(NSString *)currency properties:(NSDictionary *)props
{
    RPRPurchaseProperties *properties = [[RPRPurchaseProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"num_items"]))         { properties.numItems         = [RCTConvert NSInteger:val]; }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackPurchase:contentID value:value currency:currency properties:properties];
}

- (void)trackShare:(NSDictionary *)props
{
    RPRShareProperties *properties = [[RPRShareProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"service_name"]))      { properties.serviceName      = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_id"]))        { properties.contentID        = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackShare:properties];
}

- (void)trackLead:(NSDictionary *)props
{
    RPRLeadProperties *properties = [[RPRLeadProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"content_category"]))  { properties.contentCategory  = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }

    [Repro trackLead:properties];
}

- (void)trackCompleteRegistration:(NSDictionary *)props
{
    RPRCompleteRegistrationProperties *properties = [[RPRCompleteRegistrationProperties alloc] init];

    NSObject *val = nil;
    if ((val = props[@"value"]))             { properties.value            = [RCTConvert double:val];    }
    if ((val = props[@"currency"]))          { properties.currency         = [RCTConvert NSString:val];  }
    if ((val = props[@"status"]))            { properties.status           = [RCTConvert NSString:val];  }
    if ((val = props[@"content_name"]))      { properties.contentName      = [RCTConvert NSString:val];  }
    if ((val = props[@"extras"]))            { properties.extras       = [RCTConvert NSDictionary:val];  }


    [Repro trackCompleteRegistration:properties];
}

- (void)trackNotificationOpened:(NSString *)notificationId
{
    // Only android method
}

// Other

- (void)setLogLevel:(RPRLogLevel)level
{
    [Repro setLogLevel:level];
}

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

- (void)setPushRegistrationID:(NSString *)pushRegId
{
    // Only android method
}

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

- (void)enablePushNotification
{
    // Only android method
}

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

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

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

- (void)getNewsFeeds:(double)limit campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback
{
    if (callback == nil) {
        RCTLogWarn(@"[getNewsFeeds] callback is required. cannot return a value on success or failure.");
        return;
    }
    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:(uint64_t)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 = @{
            @"id": @(entry.ID),
            @"deviceID": entry.deviceID,
            @"title": entry.title,
            @"summary": entry.summary,
            @"body": entry.body,
            @"campaignType": @(entry.campaignType),
            @"deliveredAt": formattedDateString,
            @"linkUrl": entry.linkUrl ? [entry.linkUrl absoluteString] : @"",
            @"linkUrlString": entry.linkUrlString,
            @"imageUrl": entry.imageUrl ? [entry.imageUrl absoluteString] : @"",
            @"imageUrlString": entry.imageUrlString,
            @"shown": @(entry.shown),
            @"read": @(entry.read),
        };

        [entryJsons addObject:entryJson];
    }

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

- (void)getNewsFeedsFor:(double)limit offsetID:(double)offsetID campaignType:(nonnull NSNumber *)type callback:(RCTResponseSenderBlock)callback
{
    if (callback == nil) {
        RCTLogWarn(@"[getNewsFeedsFor] callback is required. cannot return a value on success or failure.");
        return;
    }
    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:(uint64_t)limit offsetID:(uint64_t)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 = @{
            @"id": @(entry.ID),
            @"deviceID": entry.deviceID,
            @"title": entry.title,
            @"summary": entry.summary,
            @"body": entry.body,
            @"campaignType": @(entry.campaignType),
            @"deliveredAt": formattedDateString,
            @"linkUrl": entry.linkUrl ? [entry.linkUrl absoluteString] : @"",
            @"linkUrlString": entry.linkUrlString,
            @"imageUrl": entry.imageUrl ? [entry.imageUrl absoluteString] : @"",
            @"imageUrlString": entry.imageUrlString,
            @"shown": @(entry.shown),
            @"read": @(entry.read),
        };

        [entryJsons addObject:entryJson];
    }

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

- (void)updateNewsFeeds:(NSArray<NSDictionary *> *)entryJsons callback:(RCTResponseSenderBlock)callback
{
    if (callback == nil) {
        RCTLogWarn(@"[updateNewsFeeds] callback is required. cannot return a value on success or failure.");
        return;
    }
    NSMutableArray<RPRNewsFeedEntry *> *entries = [NSMutableArray.alloc initWithCapacity:entryJsons.count];

    for (NSDictionary *entryJson in entryJsons) {
        NSDictionary *entryDic = @{
            @"newsfeed_id": [entryJson objectForKey:@"id"],
            @"device_id": [entryJson objectForKey:@"deviceID"],
            @"title": [entryJson objectForKey:@"title"],
            @"summary": [entryJson objectForKey:@"summary"],
            @"body": [entryJson objectForKey:@"body"],
            @"campaign_type": [entryJson objectForKey:@"campaignType"],
            @"delivered_at": [entryJson objectForKey:@"deliveredAt"],
            @"linkUrl": [entryJson objectForKey:@"linkUrl"],
            @"linkUrlString": [entryJson objectForKey:@"linkUrlString"],
            @"imageUrl": [entryJson objectForKey:@"imageUrl"],
            @"imageUrlString": [entryJson objectForKey:@"imageUrlString"],
            @"shown": [entryJson objectForKey:@"shown"],
            @"read": [entryJson objectForKey:@"read"],
        };
        RPRNewsFeedEntry *entry = [RPRNewsFeedEntry.alloc initWithDictionary: entryDic];
        [entries addObject:entry];
    }

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

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

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

- (void)setSilverEggProdKey:(NSString *)silverEggProdKey
{
    if (silverEggProdKey == nil) {
        return;
    }

    [Repro setSilverEggProdKey:silverEggProdKey];
}

- (void)setSilverEggCookie:(NSString *)silverEggCookie
{
    if (silverEggCookie == nil) {
        return;
    }

    [Repro setSilverEggCookie:silverEggCookie];
}

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

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

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

@end