@import UIKit;
#import "RTKRNBackgroundTimer.h"
#import "RTKLogger.h"

@implementation RTKRNBackgroundTimer {
    UIBackgroundTaskIdentifier bgTask;
    int delay;
    bool hasListeners;
}

- (BOOL)canSendEvents {
    return self.bridge != nil;
}

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

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

RCT_EXPORT_MODULE()

- (NSArray<NSString *> *)supportedEvents { return @[@"backgroundTimer", @"backgroundTimer.timeout"]; }

- (void) _start
{
    [RTKLogger debug:@"RTKRNBackgroundTimer: Starting background task"];
    [self _stop];
    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"RNBackgroundTimer" expirationHandler:^{
        [RTKLogger warning:@"RTKRNBackgroundTimer: Background task expired"];
        // Clean up any unfinished task business by marking where you
        // stopped or ending the task outright.
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    
    UIBackgroundTaskIdentifier thisBgTask = bgTask;
    [RTKLogger debug:@"RTKRNBackgroundTimer: Background task started with ID: %d", (int)thisBgTask];
    dispatch_async(dispatch_get_main_queue(), ^{
        if (hasListeners && [self canSendEvents] && thisBgTask == bgTask) {
            [self sendEventWithName:@"backgroundTimer" body:[NSNumber numberWithInt:(int)thisBgTask]];
        }
    });
}

- (void) _stop
{
    if (bgTask != UIBackgroundTaskInvalid) {
        [RTKLogger debug:@"RTKRNBackgroundTimer: Stopping background task with ID: %d", (int)bgTask];
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }
}

RCT_EXPORT_METHOD(start:(double)_delay
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    [RTKLogger debug:@"RTKRNBackgroundTimer: start() called with delay: %f", _delay];
    delay = _delay;
    [self _start];
    resolve([NSNumber numberWithBool:YES]);
}

RCT_EXPORT_METHOD(stop:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    [RTKLogger debug:@"RTKRNBackgroundTimer: stop() called"];
    [self _stop];
    resolve([NSNumber numberWithBool:YES]);
}

RCT_EXPORT_METHOD(setTimeout:(int)timeoutId
                     timeout:(double)timeout
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    __block UIBackgroundTaskIdentifier task = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"RNBackgroundTimer" expirationHandler:^{
        [RTKLogger warning:@"RTKRNBackgroundTimer: setTimeout task expired for timeoutId: %d", timeoutId];
        [[UIApplication sharedApplication] endBackgroundTask:task];
    }];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
        if (hasListeners && [self canSendEvents]) {
            [self sendEventWithName:@"backgroundTimer.timeout" body:[NSNumber numberWithInt:timeoutId]];
        }
        [[UIApplication sharedApplication] endBackgroundTask:task];
    });
    resolve([NSNumber numberWithBool:YES]);
}

RCT_EXPORT_METHOD(backgroundTimerSetTimeout:(int)timeoutId
                  timeout:(double)timeout)
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
        if (hasListeners && [self canSendEvents]) {
            [self sendEventWithName:@"backgroundTimer.timeout" body:[NSNumber numberWithInt:timeoutId]];
        }
    });
}

@end

