#import "TencentCloudPush.h"
#import <React/RCTLog.h>
#import <TIMPush/TIMPush.h>
#import <Foundation/Foundation.h>

@interface TencentCloudPush()<TIMPushListener>

@end

@implementation TencentCloudPush

{
  bool hasListeners;
}

NSString* LOG_PREFIX = @"Push objectc |";

RCT_EXPORT_MODULE(TencentCloudPush)


RCT_EXPORT_METHOD(registerPush:(int)SDKAppID appKey:(nonnull NSString *)appKey onSuccess:(RCTResponseSenderBlock)onSuccess)
{
  [self setRunningPlatform];
  RCTLogInfo(@"%@ registerPush | %d %@", LOG_PREFIX, SDKAppID, appKey);
  [TIMPushManager registerPush:SDKAppID appKey:appKey succ:^(NSData * _Nonnull deviceToken) {
    NSString* ret = [self base64StringFromData:deviceToken];
    RCTLogInfo(@"%@ registerPush ok | %@", LOG_PREFIX, ret);
    onSuccess(@[ret]);
  } fail:^(int code, NSString * _Nonnull desc) {
    RCTLogInfo(@"%@ registerPush failed | %d %@", LOG_PREFIX, code, desc);
  }];
}

RCT_EXPORT_METHOD(registerPushWithOnError:(int)SDKAppID appKey:(nonnull NSString *)appKey onSuccess:(RCTResponseSenderBlock)onSuccess onError:(RCTResponseSenderBlock)onError)
{
  [self setRunningPlatform];
  RCTLogInfo(@"%@ registerPushWithOnError | %d %@", LOG_PREFIX, SDKAppID, appKey);
  [TIMPushManager registerPush:SDKAppID appKey:appKey succ:^(NSData * _Nonnull deviceToken) {
    NSString* ret = [self base64StringFromData:deviceToken];
    RCTLogInfo(@"%@ registerPushWithOnError ok | %@", LOG_PREFIX, ret);
    onSuccess(@[ret]);
  } fail:^(int code, NSString * _Nonnull desc) {
    RCTLogInfo(@"%@ registerPushWithOnError failed | %d %@", LOG_PREFIX, code, desc);
    onError(@[[NSNumber numberWithInt:code], desc]);
  }];
}

RCT_EXPORT_METHOD(setRegistrationID:(nonnull NSString *)registrationID onSuccess:(RCTResponseSenderBlock)onSuccess)
{
  RCTLogInfo(@"%@ setRegistrationID | %@", LOG_PREFIX, registrationID);
  [TIMPushManager setRegistrationID:registrationID callback:^{
    RCTLogInfo(@"%@ setRegistrationID ok", LOG_PREFIX);
    onSuccess(@[]);
  }];
}

RCT_EXPORT_METHOD(getRegistrationID:(RCTResponseSenderBlock)onSuccess)
{
  RCTLogInfo(@"%@ getRegistrationID", LOG_PREFIX);
  [TIMPushManager getRegistrationID:^(NSString * _Nonnull value) {
    RCTLogInfo(@"%@ getRegistrationID ok | %@", LOG_PREFIX, value);
    onSuccess(@[value]);
  }];
}

RCT_EXPORT_METHOD(unRegisterPush:(RCTResponseSenderBlock)onSuccess)
{
  RCTLogInfo(@"%@ unRegisterPush", LOG_PREFIX);
  [TIMPushManager unRegisterPush:^{
    RCTLogInfo(@"%@ unRegisterPush ok", LOG_PREFIX);
    onSuccess(@[]);
  } fail:^(int code, NSString * _Nonnull desc) {
    RCTLogInfo(@"%@ unRegisterPush failed | %d %@", LOG_PREFIX, code, desc);
  }];
}


RCT_EXPORT_METHOD(unRegisterPushWithOnError:(RCTResponseSenderBlock)onSuccess onError:(RCTResponseSenderBlock)onError)
{
  RCTLogInfo(@"%@ unRegisterPushWithOnError", LOG_PREFIX);
  [TIMPushManager unRegisterPush:^{
    RCTLogInfo(@"%@ unRegisterPushWithOnError ok", LOG_PREFIX);
    onSuccess(@[]);
  } fail:^(int code, NSString * _Nonnull desc) {
    RCTLogInfo(@"%@ unRegisterPushWithOnError failed | %d %@", LOG_PREFIX, code, desc);
    onError(@[[NSNumber numberWithInt:code], desc]);
  }];
}

RCT_EXPORT_METHOD(getNotificationExtInfo:(RCTResponseSenderBlock)onSuccess)
{
  RCTLogInfo(@"%@ getNotificationExtInfo", LOG_PREFIX);
  [TIMPushManager callExperimentalAPI:@"getNotificationExtInfo" param:nil succ:^(NSObject * _Nonnull object) {
    NSString* ret = [NSString stringWithFormat:@"%@", object];
    RCTLogInfo(@"%@ getNotificationExtInfo ok | %@", LOG_PREFIX, ret);
    onSuccess(@[ret]);
  } fail:^(int code, NSString * _Nonnull desc) {
    RCTLogInfo(@"%@ getNotificationExtInfo failed | %d %@", LOG_PREFIX, code, desc);
  }];
}

- (void)setRunningPlatform {
    NSMutableDictionary *param = [NSMutableDictionary dictionary];
    param[@"runningPlatform"] = @(5);
    NSData *dataParam = [NSJSONSerialization dataWithJSONObject:param options:NSJSONWritingPrettyPrinted error:nil];
    NSString *strParam = [[NSString alloc] initWithData:dataParam encoding:NSUTF8StringEncoding];
  [TIMPushManager callExperimentalAPI:@"setPushConfig" param:strParam succ:^(NSObject * _Nonnull object) {
    NSString* ret = [NSString stringWithFormat:@"%@", object];
    RCTLogInfo(@"%@ setPushConfig ok | %@", LOG_PREFIX, ret);
  } fail:^(int code, NSString * _Nonnull desc) {
    RCTLogInfo(@"%@ setPushConfig failed | %d %@", LOG_PREFIX, code, desc);
  }];
}

- (NSString *)base64StringFromData:(NSData *)data {
    if (data == nil) {
        return @"";
    }
    return [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}

- (NSString *)convertNSObjectToJsonString:(NSObject *)object {
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error];
    
    if (!jsonData) {
        RCTLogInfo(@"Error converting object to JSON: %@", error);
        return nil;
    } else {
        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
        return jsonString;
    }
}

- (void)addPushListener {
  RCTLogInfo(@"%@ addPushListener", LOG_PREFIX);
  [TIMPushManager addPushListener: self];
}

- (void)removePushListener {
  RCTLogInfo(@"%@ removePushListener", LOG_PREFIX);
  [TIMPushManager removePushListener: self];
}

- (void)onRecvPushMessage:(TIMPushMessage *)message {
  NSDictionary *data = @{
    @"title": message.title,
    @"desc": message.desc,
    @"ext": message.ext,
    @"messageID": message.messageID
  };
  NSString *jsonString = [self convertNSObjectToJsonString:data];
  if (hasListeners) {
    [self sendEventWithName:@"message_received" body:@{@"data": jsonString}];
  }
}

- (void)onRevokePushMessage:(NSString *)messageID {
  if (hasListeners) {
    [self sendEventWithName:@"message_revoked" body:@{@"data": messageID}];
  }
}

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

// Will be called when this module's first listener is add.
-(void)startObserving {
    hasListeners = YES;
    [self addPushListener];
}

// Will be called when this module's last listener is removed.
-(void)stopObserving {
    hasListeners = NO;
    [self removePushListener];
}

@end