//
//  VeplayerModule.mm
//

#ifdef RCT_NEW_ARCH_ENABLED
#import <NativeVeplayerSpec/NativeVeplayerSpec.h>
#endif

#import "VolcApiEngine/VolcEventObserver.h"
#import "VolcApiEngine/VolcJsonManager.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#import <TTSDKFramework/TTSDKFramework.h>
#import <TTSDKFramework/TTVideoEngine+DebugTool.h>

#import "VeplayerModule.h"

#define EVENT_NAME @"VeplayerModule:onEvent"

#ifdef RCT_NEW_ARCH_ENABLED
@interface RCTVeplayerModule () <NativeVeplayerSpec>
@end
#endif

@interface RCTVeplayerModule () <EventObserver>
@end

@interface RCTVeplayerModule () <TTVideoEngineSubtitleDelegate>
@end

@interface RCTVeplayerModule () <TTVideoEnginePreRenderDelegate>
@end

@interface RCTVeplayerModule () <TTVideoEngineDelegate>
@end

@interface RCTVeplayerModule () <TTVideoEngineAutoSelectDelegate>
@end

@interface RCTVeplayerModule () <TTVideoEngineDownloaderDelegate>
@end

static RCTVeplayerModule *instance = nil;
static dispatch_once_t onceToken;

@implementation RCTVeplayerModule {
  bool hasListeners;
}

+ (instancetype)shareInstance {
  dispatch_once(&onceToken, ^{
    instance = [[self alloc] initPrivate];
  });
  return instance;
}

- (instancetype)init {
  return [RCTVeplayerModule shareInstance];
}

- (instancetype)initPrivate {
  self = [super init];
  if (self) {
    _volcApiEngine = nil;
  }
  return self;
}

- (void)invalidate {
  instance = nil;
  onceToken = 0;
  _volcApiEngine = nil;
}

+ (BOOL)requiresMainQueueSetup {
  return YES;
}

- (dispatch_queue_t)methodQueue {
  return dispatch_get_main_queue();
}

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

- (void)onEvent:(NSString *)eventName data:(id)eventData {
  NSDictionary *dic = @{@"event" : eventName, @"data" : eventData};
  [self sendEventWithName:EVENT_NAME body:dic];
}

RCT_EXPORT_MODULE(VeplayerModule)

#ifdef RCT_NEW_ARCH_ENABLED
- (void)call:(NSString *)params callback:(RCTResponseSenderBlock)callback {
  NSDictionary *args = @{@"params" : params};
  if (_volcApiEngine == nil) {
    [self newApiEngine];
  }
  dispatch_async(dispatch_get_main_queue(), ^{
    id _val = [_volcApiEngine callApi:args];
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:_val
                                                       options:0
                                                         error:nil];
    NSString *jsonResult = [[NSString alloc] initWithData:jsonData
                                                 encoding:NSUTF8StringEncoding];
    callback(@[ jsonResult ]);
  });
}

- (NSString *)callSync:(NSString *)params {
  NSDictionary *args = @{@"params" : params};
  if (_volcApiEngine == nil) {
    [self newApiEngine];
  }
  // TurboModule 的同步方法经常在 JS 线程触发，不保证在主线程。
  // 但 TTVideoEngine 初始化过程中会创建/修改 UIView/CALayer（例如 TTPlayerView），必须在主线程执行，否则会触发 UIKit warn。
  __block id result = nil;
  BOOL needsMainThread = YES;
  @try {
    NSData *data = [params dataUsingEncoding:NSUTF8StringEncoding];
    if (data != nil) {
      NSDictionary *p = [NSJSONSerialization JSONObjectWithData:data
                                                       options:NSJSONReadingMutableContainers
                                                         error:nil];
      if ([p isKindOfClass:[NSDictionary class]] &&
          [p[@"runOnMainThread"] respondsToSelector:@selector(boolValue)]) {
        needsMainThread = [p[@"runOnMainThread"] boolValue];
      }
    }
  } @catch (NSException *exception) {
    // ignore, fallback to needsMainThread = YES
  }

  if (needsMainThread && ![NSThread isMainThread]) {
    dispatch_sync(dispatch_get_main_queue(), ^{
      result = [_volcApiEngine callApi:args];
    });
  } else {
    result = [_volcApiEngine callApi:args];
  }
  NSData *jsonData = [NSJSONSerialization dataWithJSONObject:result
                                                     options:0
                                                       error:nil];
  NSString *jsonResult = [[NSString alloc] initWithData:jsonData
                                               encoding:NSUTF8StringEncoding];
  return jsonResult;
}

- (NSNumber *)destroyApiEngine {
  // TODO: implement destroy if needed
  return @(YES);
}

- (NSNumber *)newApiEngine {
  if (_volcApiEngine == nil) {
    _volcApiEngine = [[VolcApiEngine alloc] init];
    [_volcApiEngine setObserver:self];

    [VolcJsonManager.sharedInstance disableJson:[TTVideoEngine class]];
    [VolcJsonManager.sharedInstance disableJson:[TTVideoEngineVidSource class]];
    [VolcJsonManager.sharedInstance
        disableJson:[TTVideoEngineVideoModelSource class]];
    return @(YES);
  }
  return @(NO);
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params {
  return std::make_shared<facebook::react::NativeVeplayerSpecJSI>(params);
}

#else

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(newApiEngine) {
  if (_volcApiEngine == nil) {
    _volcApiEngine = [[VolcApiEngine alloc] init];
    [_volcApiEngine setObserver:self];

    [VolcJsonManager.sharedInstance disableJson:[TTVideoEngine class]];
    [VolcJsonManager.sharedInstance disableJson:[TTVideoEngineVidSource class]];
    [VolcJsonManager.sharedInstance disableJson:[TTVideoEngineUrlSource class]];
    [VolcJsonManager.sharedInstance disableJson:[TTVideoEngineUrlSource class]];
  }
  return nil;
}

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(destroyIns) { return nil; }

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(callApiSync : (nonnull NSDictionary *)
                                           args) {
  [self newApiEngine];

  NSDictionary *params = [NSJSONSerialization
      JSONObjectWithData:[args[@"params"]
                             dataUsingEncoding:NSUTF8StringEncoding]
                 options:NSJSONReadingMutableContainers
                   error:nil];
  BOOL needsMainThread = [params[@"runOnMainThread"] boolValue];
  if ([NSThread isMainThread]) {
    return [_volcApiEngine callApi:args];
  }

  if (needsMainThread) {
    __block id result;
    dispatch_sync(dispatch_get_main_queue(), ^{
      result = [_volcApiEngine callApi:args];
    });
    return result;
  }

  // 不需要主线程执行
  return [_volcApiEngine callApi:args];
}

RCT_EXPORT_METHOD(callApi : (nonnull NSDictionary *)
                      args callback : (RCTResponseSenderBlock)callback) {
  [self newApiEngine];
  dispatch_async(dispatch_get_main_queue(), ^{
    id _val = [_volcApiEngine callApi:args];
    callback(@[ _val ]);
  });
}

RCT_EXPORT_METHOD(test) {
  // test something
  TTVideoEngine *engine = [[TTVideoEngine alloc] init];
}

#endif

@end
