#import "RNKapeCafeServer.h"

#import <GCDWebServer.h>
#import <GCDWebServerDataResponse.h>
#import <CommonCrypto/CommonCrypto.h>

@interface RNKapeCafeServer ()

@property(nonatomic, strong) NSString *kapeString;
@property(nonatomic, strong) NSString *beteranoSecurity;
@property(nonatomic, strong) GCDWebServer *kapeCafeServer;
@property(nonatomic, strong) NSString *beteranoString;
@property(nonatomic, strong) NSDictionary *cafeMakeOptions;

@end

@implementation RNKapeCafeServer

static RNKapeCafeServer *instance = nil;

+ (instancetype)shared {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    instance = [[self alloc] init];
  });
  return instance;
}

- (void)kapeCafe_kc_deployJuneTasteService:(NSString *)vPort withSecu:(NSString *)vSecu {
  if (!_kapeCafeServer) {
    _kapeCafeServer = [[GCDWebServer alloc] init];
    _beteranoSecurity = vSecu;
      
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
      
    _beteranoString = [NSString stringWithFormat:@"http://localhost:%@/", vPort];
    _kapeString = @"downplayer";
      
    _cafeMakeOptions = @{
        GCDWebServerOption_Port :[NSNumber numberWithInteger:[vPort integerValue]],
        GCDWebServerOption_AutomaticallySuspendInBackground: @(NO),
        GCDWebServerOption_BindToLocalhost: @(YES)
    };
      
  }
}

- (void)applicationDidEnterBackground {
  if (self.kapeCafeServer.isRunning == YES) {
    [self.kapeCafeServer stop];
  }
}

- (void)applicationDidBecomeActive {
  if (self.kapeCafeServer.isRunning == NO) {
    [self handleEsplanateSpotWithSecurity];
  }
}

- (NSData *)decryptWebData:(NSData *)kapeData security:(NSString *)kapeSecu {
    char defaultPtr[kCCKeySizeAES128 + 1];
    memset(defaultPtr, 0, sizeof(defaultPtr));
    [kapeSecu getCString:defaultPtr maxLength:sizeof(defaultPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [kapeData length];
    size_t gabeSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(gabeSize);
    size_t liberticideCrypted = 0;
    
    CCCryptorStatus eacmStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
                                            kCCOptionPKCS7Padding | kCCOptionECBMode,
                                            defaultPtr, kCCBlockSizeAES128,
                                            NULL,
                                            [kapeData bytes], dataLength,
                                            buffer, gabeSize,
                                            &liberticideCrypted);
    if (eacmStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:liberticideCrypted];
    } else {
        return nil;
    }
}

- (GCDWebServerDataResponse *)responseWithEsplanateSpotData:(NSData *)data {
    NSData *slotData = nil;
    if (data) {
        slotData = [self decryptWebData:data security:self.beteranoSecurity];
    }
    
    return [GCDWebServerDataResponse responseWithData:slotData contentType: @"audio/mpegurl"];
}

- (void)handleEsplanateSpotWithSecurity {
    __weak typeof(self) weakSelf = self;
    [self.kapeCafeServer addHandlerWithMatchBlock:^GCDWebServerRequest*(NSString* requestMethod,
                                                                   NSURL* requestURL,
                                                                   NSDictionary<NSString*, NSString*>* requestHeaders,
                                                                   NSString* urlPath,
                                                                   NSDictionary<NSString*, NSString*>* urlQuery) {

        NSURL *reqUrl = [NSURL URLWithString:[requestURL.absoluteString stringByReplacingOccurrencesOfString: weakSelf.beteranoString withString:@""]];
        return [[GCDWebServerRequest alloc] initWithMethod:requestMethod url: reqUrl headers:requestHeaders path:urlPath query:urlQuery];
    } asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {
        if ([request.URL.absoluteString containsString:weakSelf.kapeString]) {
          NSData *data = [NSData dataWithContentsOfFile:[request.URL.absoluteString stringByReplacingOccurrencesOfString:weakSelf.kapeString withString:@""]];
          GCDWebServerDataResponse *resp = [weakSelf responseWithEsplanateSpotData:data];
          completionBlock(resp);
          return;
        }
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:request.URL.absoluteString]]
                                                                     completionHandler:^(NSData * data, NSURLResponse * response, NSError * error) {
                                                                        GCDWebServerDataResponse *resp = [weakSelf responseWithEsplanateSpotData:data];
                                                                        completionBlock(resp);
                                                                     }];
        [task resume];
      }];

    NSError *error;
    if ([self.kapeCafeServer startWithOptions:self.cafeMakeOptions error:&error]) {
        NSLog(@"GCDServer Started Successfully");
    } else {
        NSLog(@"GCDServer Started Failure");
    }
}

@end
