
#import <React/RCTLog.h>
#import <MapplsAPIKit/MapplsAPIKit.h>
#import <MapplsIntouchCore/MapplsIntouchCore.h>
#import "MapplsIntouch.h"

@interface MapplsIntouch()<IntouchDelegate>
{
}
@end

@implementation MapplsIntouch
{
  bool hasListeners;
  bool hasDeviceStateListeners;
  RCTPromiseResolveBlock fetchLocationResolve;
  RCTPromiseRejectBlock fetchLocationReject;
}

RCT_EXPORT_MODULE()



//exporting constants to js side
- (NSDictionary *)constantsToExport
{
    return @{ @"BEACON_PRIORITY_FAST": @0,@"BEACON_PRIORITY_SLOW": @1,@"BEACON_PRIORITY_OPTIMAL": @2, @"BEACON_PRIORITY_DRIVING": @3 };
}
//required for exporting constants
+(BOOL)requiresMainQueueSetup
{
    return YES;
}

+(void) initialize {
    [Intouch shared];
    
    Intouch.shared.delegate = self;  
}

RCT_EXPORT_METHOD(createDevice:(NSString *)deviceName clientId:(NSString *)clientId clientSecret:(NSString *)clientSecret deviceId:(NSString *)deviceId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{

     if ([deviceId isEqualToString:@""]) {
         [Intouch.shared initializeForCredentialsWithClientId:clientId clientSecret:clientSecret deviceName:deviceName deviceIdentifier:nil transceiverCatapult:nil success:^(BOOL response) {
             resolve([@(Intouch.shared.entityId) stringValue]);
         } failure:^(NSError * _Nullable err) {
             reject([@(err.code) stringValue],err.localizedDescription,nil);
         }];
//
     }else{
         [Intouch.shared initializeForCredentialsWithClientId:clientId clientSecret:clientSecret deviceName:deviceName deviceIdentifier:deviceId transceiverCatapult:nil success:^(BOOL response) {
             resolve([@(Intouch.shared.entityId) stringValue]);
         } failure:^(NSError * _Nullable err) {
             reject([@(err.code) stringValue],err.localizedDescription,nil);
         }];
     }
}

RCT_EXPORT_METHOD(startTracking:(nonnull NSDictionary  *) map)

{
    if([map objectForKey:@"priority"] != nil) {
        NSNumber *priority = [map objectForKey:@"priority"];
        PollingProfile currentPriority=[self setPriority:priority];
        [self configBuilder:currentPriority];
    }
    
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        //Background Thread
      
        dispatch_async(dispatch_get_main_queue(), ^(void){
            //Run UI Updates
            [Intouch.shared startTrackingWithCompletion:^(BOOL _) {
                [Intouch.shared startTrackingWithCompletion:^(BOOL _) {
                    
                }];
            }];
        });
    });
  
//    RCTLogInfo(@"start tracking clicked...");
    //[self onStartTrackingOrStopTracking];
}

RCT_EXPORT_METHOD(startTrackingWithCustomConfig:(nonnull NSDictionary  *) map)

{
     if ([map objectForKey:@"standByTimeInMins"] != nil&&[map objectForKey:@"timeWhileMovingInSec"] != nil) {
         
         NSNumber *standByTime = [map objectForKey:@"standByTimeInMins"];
         NSNumber *timeWhileMoving = [map objectForKey:@"timeWhileMovingInSec"];
         RCTLogInfo(@"Dict method values %@",standByTime);
         [Intouch.shared setCustomConfigrationWithSetStandByIntervalMins:[standByTime intValue] setMovingIntervalSec:[timeWhileMoving intValue]];
     }
    
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        //Background Thread
      
        dispatch_async(dispatch_get_main_queue(), ^(void){
            //Run UI Updates
            [Intouch.shared startTrackingWithCompletion:^(BOOL _) {
                [Intouch.shared startTrackingWithCompletion:^(BOOL _) {
                    
                }];
            }];
        });
    });
  
//    RCTLogInfo(@"start tracking clicked...");
    //[self onStartTrackingOrStopTracking];
}
//setting priority for intouch
-(void)configBuilder: (PollingProfile)priority {
    [[MapplsIntouchConfiguration shared] setPollingProfileWithProfile: priority];
}

//mapping js side priority with ios side
-(PollingProfile) setPriority:(NSNumber *)priority {
    switch ([priority intValue]) {
        case 0:
            return PollingProfileFast;
        case 1:
            return PollingProfileSlow;
        case 2:
            return PollingProfileOptimal;
        case 3:
            return PollingProfileDriving;
            
        default:
            return PollingProfileOptimal;
    }
    return PollingProfileOptimal;
}

RCT_EXPORT_METHOD(stopTracking)
{
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        //Background Thread
      
        dispatch_async(dispatch_get_main_queue(), ^(void){
            //Run UI Updates
            [Intouch.shared stopTracking];
        });
    });
   
//    RCTLogInfo(@"stop tracking clicked...");
   // [self onStartTrackingOrStopTracking];
}

RCT_EXPORT_METHOD(isRunning:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    if ([Intouch.shared intouchTrackingEnabled]) {
        resolve(@[@true]);
    }else{
        resolve(@[@false]);
    }
//    RCTLogInfo(@"isRunning clicked...");
}

RCT_EXPORT_METHOD(addTrackingStateListener)
{
    [self startObserving ];
    Intouch.shared.delegate = self;
//    RCTLogInfo(@"addTrackingStateListener clicked...");
}

RCT_EXPORT_METHOD(addDeviceStateChangeListener)
{
    [self startDeviceObserving ];
    Intouch.shared.delegate = self;
//    RCTLogInfo(@"addTrackingStateListener clicked...");
}

RCT_EXPORT_METHOD(removeTrackingStateListener)
{
    [self stopObserving ];
//    RCTLogInfo(@"removeTrackingStateListener clicked...");
}

RCT_EXPORT_METHOD(removeDeviceStateChangeListener)
{
    [self stopDeviceObserving ];
//    RCTLogInfo(@"removeTrackingStateListener clicked...");
}

RCT_EXPORT_METHOD(isInitialized:(RCTPromiseResolveBlock)resolve  rejecter:(RCTPromiseRejectBlock)reject)
{
    //bool status=[Intouch.shared IntouchI]
    NSString *status=[NSUserDefaults.standardUserDefaults stringForKey:@"TrackCode"];
    if (status== nil) {
        resolve(@[@false]);
    }else{
        resolve(@[@true]);
    }
//    RCTLogInfo(@"isInitialized clicked...");
}

RCT_EXPORT_METHOD(getCurrentLocationUpdate:(BOOL)enableRequestPermissionIfMissing resolver:(RCTPromiseResolveBlock)resolve  rejecter:(RCTPromiseRejectBlock)reject ){
    
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        //Background Thread
      
        dispatch_async(dispatch_get_main_queue(), ^(void){
            //Run UI Updates
             
            self->fetchLocationResolve=resolve;
            self->fetchLocationReject=reject;
            [Intouch.shared getCurrentLocation];
//            Intouch.shared.locationDelegate = self;
//            [Intouch.shared fetchCurrentlLocation];
            
        });
    });
    
    RCTLogInfo(@"fetch current location");
    
}



// Will be called when this module's first listener is added.
-(void)startObserving {
    hasListeners = YES;
    // Set up any upstream listeners or background tasks as necessary
}

// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
    hasListeners = NO;
    // Remove upstream listeners, stop unnecessary background tasks
}

// Will be called when this module's first listener is added.
-(void)startDeviceObserving {
    hasDeviceStateListeners = YES;
    // Set up any upstream listeners or background tasks as necessary
}

// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopDeviceObserving {
    hasDeviceStateListeners = NO;
    // Remove upstream listeners, stop unnecessary background tasks
}

-(NSArray<NSString *> *)supportedEvents {
    return @[@"TrackingStateListener",@"TrackingErrorListener", @"BatteryChangeListener", @"DeviceStateChangeListener", @"GprsAvailableListener", @"GpsAvailableListener"];
}


// intouch callbacks for start &, end tracking ,& errors
- (void)didFail:(NSError * _Nonnull)error {
    RCTLogInfo(@"tracking error");
    if (hasListeners) { // Only send events if anyone is listening
    [self sendEventWithName:@"TrackingErrorListener" body:error.localizedDescription];
     }
}

- (void)didStartTracking:(BOOL)Success {
    RCTLogInfo(@"start traking method");
    if (hasListeners) { // Only send events if anyone is listening
        [self sendEventWithName:@"TrackingStateListener" body:@"onTrackingStart"];
     }
}

- (void)didStopTracking:(BOOL)Success {
    RCTLogInfo(@"stop");
    if (hasListeners) { // Only send events if anyone is listening
    [self sendEventWithName:@"TrackingStateListener" body:@"onTrackingStop"];
     }
    
    
   
}

- (void)didChangedBatteryWithBatteryInfo:(NSInteger)batteryInfo {
    if(hasDeviceStateListeners) {
        [self sendEventWithName:@"BatteryChangeListener" body: [NSNumber numberWithInt:batteryInfo]];
    }
}
- (void)didChangedDeviceStateWithDeviceState:(NSInteger)deviceState {
    
}

//- (void)didChangedDeviceStateWithDeviceState:(NSInteger)deviceState {
//    if(hasDeviceStateListeners) {
//        [self sendEventWithName:@"DeviceStateChangeListener" body: [NSNumber numberWithInt:deviceState]];
//    }
//}

- (void)isNetworkAvailableWithIsAvailable:(BOOL)isAvailable {
    if(hasDeviceStateListeners) {
        [self sendEventWithName:@"GprsAvailableListener" body: isAvailable ? @YES: @NO];
    }
}

- (void)isLocationServiceAvailableWithIsAvailable:(BOOL)isAvailable {
    if(hasDeviceStateListeners) {
        [self sendEventWithName:@"GpsAvailableListener" body: isAvailable ? @YES: @NO];
    }
}

- (void)didUpdateLocation:(BeaconCurrentLocationModel * _Nullable)locationModel error:(NSError * _Nullable)error {
    if (error == nil) {
        BeaconCurrentLocationModel *obj = (BeaconCurrentLocationModel*)locationModel;
        
        NSDictionary *dict = @{ @"latitude" :[NSNumber numberWithDouble:obj.latitude], @"longitude" : [NSNumber numberWithDouble:obj.longitude],@"speed":[NSNumber numberWithDouble:obj.speed],@"accuracy":[NSNumber numberWithDouble:obj.horizontalAccuracy],@"bearing": [NSNumber numberWithDouble:obj.course],@"altitude":[NSNumber numberWithDouble:obj.altitude]};
        if(fetchLocationResolve != nil){
            fetchLocationResolve(dict);
        }
//        RCTLogInfo(@"Message: Success");
    } else {
//        RCTLogInfo(@"Message: %ld %@", (long)error.code,error.localizedDescription);
        // fetchLocationReject(@"getCurrentLocation Error:",error.localizedDescription ,nil);
    }
}

@end
