//
//  RCTConvert+ContextCenter.m
//  RNContextCenter
//
//  Created by Shaffiulla Khan on 09/01/19.
//  Copyright © 2019 Impekable LLC. All rights reserved.
//

#import "RCTConvert+ContextCenter.h"
#import <React/RCTUtils.h>

@implementation RCTConvert (ContextCenter)

RCT_ENUM_CONVERTER(TCHUserUpdate,(@{@"Attributes" : @(TCHUserUpdateAttributes),
                                    @"FriendlyName" : @(TCHUserUpdateFriendlyName),
                                    @"ReachabilityOnline": @(TCHUserUpdateReachabilityOnline),
                                    @"ReachabilityNotifiable": @(TCHUserUpdateReachabilityNotifiable)}), TCHUserUpdateFriendlyName, integerValue)

RCT_ENUM_CONVERTER(TCHLogLevel,(@{@"Info" : @(TCHLogLevelInfo),
                                  @"Fatal" : @(TCHLogLevelFatal),
                                  @"Debug" : @(TCHLogLevelDebug),
                                  @"Warning" : @(TCHLogLevelWarning),
                                  @"Critical" : @(TCHLogLevelCritical)}), TCHLogLevelFatal, integerValue)

RCT_ENUM_CONVERTER(TCHChannelType,(@{@"Public" : @(TCHChannelTypePublic),
                                     @"Private" : @(TCHChannelTypePrivate)}), TCHChannelTypePublic, integerValue)

RCT_ENUM_CONVERTER(TCHChannelStatus,(@{@"Joined" : @(TCHChannelStatusJoined),
                                       @"Invited" : @(TCHChannelStatusInvited),
                                       @"NotParticipating" : @(TCHChannelStatusNotParticipating)}), TCHChannelStatusInvited, integerValue)

RCT_ENUM_CONVERTER(TCHClientConnectionState,(@{@"Error" : @(TCHClientConnectionStateError),
                                               @"Denied" : @(TCHClientConnectionStateDenied),
                                               @"Unknown" : @(TCHClientConnectionStateUnknown),
                                               @"Connected" : @(TCHClientConnectionStateConnected),
                                               @"Connecting" : @(TCHClientConnectionStateConnecting),
                                               @"Disconnected" : @(TCHClientConnectionStateDisconnected)}), TCHClientConnectionStateUnknown, integerValue)

RCT_ENUM_CONVERTER(TCHClientSynchronizationStatus,(@{@"Failed" : @(TCHClientSynchronizationStatusFailed),
                                                     @"Started" : @(TCHClientSynchronizationStatusStarted),
                                                     @"Completed" : @(TCHClientSynchronizationStatusCompleted),
                                                     @"ChannelsListCompleted" : @(TCHClientSynchronizationStatusChannelsListCompleted)}), TCHClientSynchronizationStatusStarted, integerValue)

RCT_ENUM_CONVERTER(TCHChannelSynchronizationStatus,(@{@"All" : @(TCHChannelSynchronizationStatusAll),
                                                      @"None" : @(TCHChannelSynchronizationStatusNone),
                                                      @"Failed" : @(TCHChannelSynchronizationStatusFailed),
                                                      @"Metadata" : @(TCHChannelSynchronizationStatusMetadata),
                                                      @"Identifier" : @(TCHChannelSynchronizationStatusIdentifier)}), TCHChannelSynchronizationStatusNone, integerValue)

+ (NSDictionary *)twilioChatClient:(TwilioChatClient *)client{
    NSLog(@"twilioChatClient: %@", [client debugDescription]);
    if (!client) {
        return RCTNullIfNil(nil);
    }
    return @{
             @"version": RCTNullIfNil([client version]),
             @"user": RCTNullIfNil([self user:client.user]),
             @"synchronizationStatus": RCTNullIfNil(@(client.synchronizationStatus)),
             @"isReachabilityEnabled": RCTNullIfNil(@(client.isReachabilityEnabled))};
}

+ (NSDictionary *)twilioAccessManager:(TwilioAccessManager *)accessManager{
    NSLog(@"twilioAccessManager: %@", [accessManager debugDescription]);
    if (!accessManager) {
        return RCTNullIfNil(nil);
    }
    return @{@"token": RCTNullIfNil(accessManager.currentToken),
             @"expirationDate": RCTNullIfNil(@(accessManager.expiryTime.timeIntervalSince1970 * 1000))};
}

+ (NSDictionary *)member:(TCHMember *)member{
    NSLog(@"member: %@", [member debugDescription]);
    if (!member) {
        return RCTNullIfNil(nil);
    }
    //FIXME: return user details to dictionary
    //    [member subscribedUserWithCompletion:^(TCHResult *result, TCHUser *user) {
    //        if (result.isSuccessful){
    //            return @{@"userInfo": [RCTConvert user:user],
    //                     @"lastConsumedMessageIndex": RCTNullIfNil(member.lastConsumedMessageIndex),
    //                     @"lastConsumptionTimestamp": RCTNullIfNil(member.lastConsumptionTimestamp)};
    //        }else{
    //            return @{@"userIdentity": RCTNullIfNil(member.identity),
    //                     @"lastConsumedMessageIndex": RCTNullIfNil(member.lastConsumedMessageIndex),
    //                     @"lastConsumptionTimestamp": RCTNullIfNil(member.lastConsumptionTimestamp)};
    //        }
    //    }];
    return @{@"userIdentity": RCTNullIfNil(member.identity),
             @"lastConsumedMessageIndex": RCTNullIfNil(member.lastConsumedMessageIndex),
             @"lastConsumptionTimestamp": RCTNullIfNil(member.lastConsumptionTimestamp)};
}
+ (NSDictionary *)message:(TCHMessage *)message {
    NSLog(@"message: %@", [message debugDescription]);
    if (!message) {
        return RCTNullIfNil(nil);
    }
    return @{@"sid": RCTNullIfNil(message.sid),
             @"body": RCTNullIfNil(message.body),
             @"index": RCTNullIfNil(message.index),
             @"author": RCTNullIfNil(message.author),
             @"timestamp": RCTNullIfNil(message.timestamp),
             @"dateUpdated": RCTNullIfNil(message.dateUpdated),
             @"lastUpdatedBy": RCTNullIfNil(message.lastUpdatedBy),
             @"attributes": RCTNullIfNil(message.attributes),
             @"timestampAsDate": RCTNullIfNil(@(message.timestampAsDate.timeIntervalSince1970 * 1000)),
             @"dateUpdatedDate": RCTNullIfNil(@(message.dateUpdatedAsDate.timeIntervalSince1970 * 1000))};
}
+ (NSDictionary *)channel:(TCHChannel *)channel{
    NSLog(@"channel: %@", [channel debugDescription]);
    if (!channel) {
        return RCTNullIfNil(nil);
    }
    return @{@"sid": RCTNullIfNil(channel.sid),
             @"type": RCTNullIfNil(@(channel.type)),
             @"status": RCTNullIfNil(@(channel.status)),
             @"createdBy": RCTNullIfNil(channel.createdBy),
             @"uniqueName": RCTNullIfNil(channel.uniqueName),
             @"dateCreated": RCTNullIfNil(channel.dateCreated),
             @"dateUpdated": RCTNullIfNil(channel.dateUpdated),
             @"friendlyName": RCTNullIfNil(channel.friendlyName),
             @"attributes": RCTNullIfNil(channel.attributes),
             @"synchronizationStatus": RCTNullIfNil(@(channel.synchronizationStatus))};
}
+ (NSDictionary *)user:(TCHUser *)user{
    NSLog(@"user: %@", [user debugDescription]);
    if (!user) {
        return RCTNullIfNil(nil);
    }
    return @{@"identity": RCTNullIfNil(user.identity),
             @"isOnline": RCTNullIfNil(@(user.isOnline)),
             @"friendlyName": RCTNullIfNil(user.friendlyName),
             @"isNotifiable": RCTNullIfNil(@(user.isNotifiable)),
             @"attributes": RCTNullIfNil(user.attributes)};
}
+ (NSDictionary *)channelDescriptor:(TCHChannelDescriptor *)channel{
    NSLog(@"channelDescriptor: %@", [channel debugDescription]);
    if (!channel) {
        return RCTNullIfNil(nil);
    }
    return @{@"sid": RCTNullIfNil(channel.sid),
             @"createdBy": RCTNullIfNil(channel.createdBy),
             @"uniqueName": RCTNullIfNil(channel.uniqueName),
             @"friendlyName": RCTNullIfNil(channel.friendlyName),
             @"membersCount": RCTNullIfNil(@(channel.membersCount)),
             @"messageCount": RCTNullIfNil(@(channel.messagesCount)),
             @"attributes": RCTNullIfNil(channel.attributes),
             @"dateCreated": RCTNullIfNil(@(channel.dateCreated.timeIntervalSince1970 * 1000)),
             @"dateUpdated": RCTNullIfNil(@(channel.dateUpdated.timeIntervalSince1970 * 1000))};
}

+ (NSDictionary *)memberPaginator:(TCHMemberPaginator *)paginator{
    NSLog(@"memberPaginator: %@", [paginator debugDescription]);
    if (!paginator) {
        return RCTNullIfNil(nil);
    }
    return @{@"hasNextPage": @(paginator.hasNextPage),@"items": [self members:paginator.items]};
}


+ (NSDictionary *)channelDescriptorPaginator:(TCHChannelDescriptorPaginator *)paginator{
    NSLog(@"channelDescriptorPaginator: %@", [paginator debugDescription]);
    if (!paginator) {
        return RCTNullIfNil(nil);
    }
    return @{@"hasNextPage": @(paginator.hasNextPage),@"items": [self channelDescriptors:paginator.items]};
}

+ (NSDictionary *)constant{
    return @{@"TCHClientSynchronizationStatus": @{@"Started" : @(TCHClientSynchronizationStatusStarted),
                                                  @"ChannelsListCompleted" : @(TCHClientSynchronizationStatusChannelsListCompleted),
                                                  @"Completed" : @(TCHClientSynchronizationStatusCompleted),
                                                  @"Failed" : @(TCHClientSynchronizationStatusFailed)},
             @"TCHChannelSynchronizationStatus": @{@"None" : @(TCHChannelSynchronizationStatusNone),
                                                   @"Identifier" : @(TCHChannelSynchronizationStatusIdentifier),
                                                   @"Metadata" : @(TCHChannelSynchronizationStatusMetadata),
                                                   @"All" : @(TCHChannelSynchronizationStatusAll),
                                                   @"Failed" : @(TCHChannelSynchronizationStatusFailed)},
             @"TCHChannelStatus": @{@"Invited": @(TCHChannelStatusInvited),
                                    @"Joined": @(TCHChannelStatusJoined),
                                    @"NotParticipating": @(TCHChannelStatusNotParticipating)},
             @"TCHChannelType": @{@"Public": @(TCHChannelTypePublic),@"Private": @(TCHChannelTypePrivate)},
             @"TCHUserUpdate": @{@"FriendlyName": @(TCHUserUpdateFriendlyName),
                                 @"Attributes": @(TCHUserUpdateAttributes),
                                 @"ReachabilityOnline": @(TCHUserUpdateReachabilityOnline),
                                 @"ReachabilityNotifiable": @(TCHUserUpdateReachabilityNotifiable)},
             @"TCHLogLevel": @{@"Fatal" : @(TCHLogLevelFatal),
                               @"Critical" : @(TCHLogLevelCritical),
                               @"Warning" : @(TCHLogLevelWarning),
                               @"Info" : @(TCHLogLevelInfo),
                               @"Debug" : @(TCHLogLevelDebug)},
             @"TCHChannelOption": @{@"Type" : TCHChannelOptionType,
                                    @"Attributes" : TCHChannelOptionAttributes,
                                    @"UniqueName" : TCHChannelOptionUniqueName,
                                    @"FriendlyName" : TCHChannelOptionFriendlyName},
             @"TCHClientConnectionState": @{@"Unknown" : @(TCHClientConnectionStateUnknown),
                                            @"Disconnected" : @(TCHClientConnectionStateDisconnected),
                                            @"Connected" : @(TCHClientConnectionStateConnected),
                                            @"Connecting" : @(TCHClientConnectionStateConnecting),
                                            @"Denied" : @(TCHClientConnectionStateDenied),
                                            @"Error" : @(TCHClientConnectionStateError)}};
}

+ (NSArray *)members:(NSArray<TCHMember *>*)members {
    NSLog(@"members: %@", [members debugDescription]);
    if (!members) {
        return RCTNullIfNil(nil);
    }
    NSMutableArray *response = [NSMutableArray array];
    for (TCHMember *member in members) {
        [response addObject:[self member:member]];
    }
    return response;
}
+ (NSArray *)messages:(NSArray<TCHMessage *> *)messages{
    NSLog(@"messages: %@", [messages debugDescription]);
    if (!messages) {
        return RCTNullIfNil(nil);
    }
    NSMutableArray *response = [NSMutableArray array];
    for (TCHMessage *message in messages) {
        [response addObject:[self message:message]];
    }
    return response;
}
+ (NSArray *)channels:(NSArray<TCHChannel *>*)channels{
    NSLog(@"channels: %@", [channels debugDescription]);
    if (!channels) {
        return RCTNullIfNil(nil);
    }
    NSMutableArray *response = [NSMutableArray array];
    for (TCHChannel *channel in channels) {
        [response addObject:[self channel:channel]];
    }
    return response;
}
+ (NSArray *)channelDescriptors:(NSArray<TCHChannelDescriptor *>*)channels {
    NSLog(@"channelDescriptors: %@", [channels debugDescription]);
    if (!channels) {
        return RCTNullIfNil(nil);
    }
    NSMutableArray *response = [NSMutableArray array];
    for (TCHChannelDescriptor *channel in channels) {
        [response addObject:[self channelDescriptor:channel]];
    }
    return response;
}

+ (NSData *)dataWithHexString:(NSString*)hex{
    NSLog(@"dataWithHexString: %@", hex);
    // Source:  https://opensource.apple.com/source/Security/Security-55471.14.18/libsecurity_transform/NSData+HexString.m
    char buf[3];
    buf[2] = '\0';
    NSAssert(0 == [hex length] % 2, @"Hex strings should have an even number of digits (%@)", hex);
    unsigned char *bytes = malloc([hex length]/2);
    unsigned char *bp = bytes;
    for (CFIndex i = 0; i < [hex length]; i += 2) {
        buf[0] = [hex characterAtIndex:i];
        buf[1] = [hex characterAtIndex:i+1];
        char *b2 = NULL;
        *bp++ = strtol(buf, &b2, 16);
        NSAssert(b2 == buf + 2, @"String should be all hex digits: %@ (bad digit around %ld)", hex, i);
    }
    
    return [NSData dataWithBytesNoCopy:bytes length:[hex length]/2 freeWhenDone:YES];
}

@end
