//
//  RCTMPosControllerHIDProxy.m
//  RNBixolonBgateLibs
//
//  Created by OhDonggeon on 2023/11/07.
//

#import <Foundation/Foundation.h>
#import <React/RCTLog.h>
#import "RCTMPosControllerHIDProxy.h"

@import frameworkMPosSDK;

@interface RCTMPosControllerHIDProxy()
@property MPosControllerHID* hid;
@end

@implementation RCTMPosControllerHIDProxy
{
    bool hasListeners;
}

+ (BOOL)requiresMainQueueSetup {
    return NO;
}

- (id)init{
    if((self=[super init])){
        _hid = [MPosControllerHID new];
        
        [[NSNotificationCenter defaultCenter] removeObserver: self];
        
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(statusNotificationHandler:)
                                                     name: @"DataEvent"
                                                   object:nil];
        
#ifdef DEBUG
        [MPosControllerHID setEnableLog:YES saveFile:NO saveToHex:NO];
#endif
    }
    return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver: self];
}

- (void)startObserving {
    RCTLogInfo(@"startObserving");
    hasListeners = YES;
}

- (void)stopObserving {
    RCTLogInfo(@"stopObserving");
    hasListeners = NO;
}

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

RCT_EXPORT_METHOD(selectInterface:(NSInteger)interfaceType
                  address:(NSString*)address
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    MPOS_RESULT result = [_hid selectInterface:interfaceType address:address];
    NSString* resultMsg = [NSString stringWithFormat:@"RESULT_CODE: %ld",(long)result];
    if(result != MPOS_SUCCESS){
        reject(@"FAIL", resultMsg, nil);
        return;
    }
    resolve([NSNumber numberWithInteger:result]);
}

RCT_EXPORT_METHOD(selectCommandMode:(NSInteger)commandMode
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    MPOS_RESULT result = [_hid selectCommandMode:commandMode];
    NSString* resultMsg = [NSString stringWithFormat:@"RESULT_CODE: %ld",(long)result];
    if(result != MPOS_SUCCESS){
        reject(@"FAIL", resultMsg, nil);
        return;
    }
    resolve([NSNumber numberWithInteger:result]);
}

RCT_EXPORT_METHOD(openService:(NSInteger)deviceID
                  timeout:(NSInteger)timeout
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    [_hid setTimeout: timeout];
    MPOS_RESULT result = [_hid openService:deviceID];
    NSString* resultMsg = [NSString stringWithFormat:@"RESULT_CODE: %ld",(long)result];
    if(result != MPOS_SUCCESS){
        reject(@"FAIL", resultMsg, nil);
        return;
    }
    resolve([NSNumber numberWithInteger:result]);
}

RCT_EXPORT_METHOD(closeService:(NSInteger)timeout
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    MPOS_RESULT result = [_hid closeService:timeout];
    NSString* resultMsg = [NSString stringWithFormat:@"RESULT_CODE: %ld",(long)result];
    if(result != MPOS_SUCCESS){
        reject(@"FAIL", resultMsg, nil);
        return;
    }
    resolve([NSNumber numberWithInteger:result]);
}

RCT_EXPORT_METHOD(setTransaction:(NSInteger)mode
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    MPOS_RESULT result = [_hid setTransaction:mode];
    NSString* resultMsg = [NSString stringWithFormat:@"RESULT_CODE: %ld",(long)result];
    if(result != MPOS_SUCCESS){
        reject(@"FAIL", resultMsg, nil);
        return;
    }
    resolve([NSNumber numberWithInteger:result]);
}

RCT_EXPORT_METHOD(setReadMode:(NSInteger)mode
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    MPOS_RESULT result = [_hid setReadMode:mode];
    NSString* resultMsg = [NSString stringWithFormat:@"RESULT_CODE: %ld",(long)result];
    if(result != MPOS_SUCCESS){
        reject(@"FAIL", resultMsg, nil);
        return;
    }
    resolve([NSNumber numberWithInteger:result]);
}

RCT_EXPORT_METHOD(setKeepNetworkConnection:(NSInteger)enable
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    [_hid setKeepNetworkConnection:enable];
    resolve([NSNumber numberWithInteger:0]);
}

RCT_EXPORT_METHOD(getDeviceId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
    NSInteger deviceId = [_hid getDeviceId];
    if(deviceId < 0){
        reject(@"FAIL", [NSString stringWithFormat:@"DEVICE_ID: %ld",(long)deviceId], nil);
        return;
    }
    resolve([NSNumber numberWithInteger:deviceId]);
}

RCT_EXPORT_METHOD(isOpen:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
    NSInteger isOpen = [_hid isOpen];
    resolve([NSNumber numberWithInteger:isOpen]);
}

RCT_EXPORT_METHOD(directIO:(NSArray<NSNumber*>*)data
                  resolve:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    NSMutableData* dataToSend = [NSMutableData data];
    for(NSNumber* number in data){
        char byte = [number charValue];
        [dataToSend appendBytes: &byte length:1];
    }
    MPOS_RESULT result = [_hid directIO:dataToSend];
    NSString* resultMsg = [NSString stringWithFormat:@"RESULT_CODE: %ld",(long)result];
    if(result != MPOS_SUCCESS){
        reject(@"FAIL", resultMsg, nil);
        return;
    }
    resolve([NSNumber numberWithInteger:result]);
}

- (void) statusNotificationHandler:(NSNotification*) notification{
    NSNumber* deviceId = (NSNumber*)[notification object];
    
    if([deviceId integerValue] != [_hid getDeviceId])
        return;
    
    __weak typeof(self) weakSelf = self;
    
    if ([[notification name] isEqualToString: @"DataEvent"]) {
        RCTLogInfo(@"DataEvent");
        
        NSMutableArray *allKeys = [[[notification userInfo] allKeys] mutableCopy];
        
        for (NSString *key in allKeys) {
            NSData* data = [[notification userInfo] objectForKey: key];
            
            dispatch_async(dispatch_get_main_queue(),^{
                typeof(self) strongSelf = weakSelf;
                
                if(strongSelf->hasListeners){
                    [strongSelf sendEventWithName:@"HIDDataEvent" body:@{
                        @"deviceid":deviceId,
                        @"data":[self convertNSDataToNSNumberArray:data]
                    }];
                }
            });
        }
    }
}

- (NSArray<NSNumber *> *)convertNSDataToNSNumberArray:(NSData *)data {
    const uint8_t *bytes = [data bytes];
    
    NSMutableArray<NSNumber *> *numberArray = [NSMutableArray array];
    
    for (NSUInteger i = 0; i < [data length]; i++) {
        NSNumber *number = [NSNumber numberWithUnsignedChar:bytes[i]];
        [numberArray addObject:number];
    }
    
    return [numberArray copy];
}

RCT_EXPORT_MODULE();

@end
