#import <React/RCTConvert.h>
#import "RNZoomVideoSdk.h"
#import "RNZoomVideoSdkVideoHelper.h"
#import "RCTConvert+RNZoomVideoSdk.h"

@implementation RNZoomVideoSdkVideoHelper

- (ZoomVideoSDKVideoHelper *)getVideoHelper
{
    ZoomVideoSDKVideoHelper* videoHelper = nil;
    @try {
        videoHelper = [[ZoomVideoSDK shareInstance] getVideoHelper];
        if (videoHelper == nil) {
            NSException *e = [NSException exceptionWithName:@"NoVideoHelperFound" reason:@"No Video Helper Found" userInfo:nil];
            @throw e;
        }
    } @catch (NSException *e) {
        NSLog(@"%@ - %@", e.name, e.reason);
    }
    return videoHelper;
}

RCT_EXPORT_MODULE()

RCT_EXPORT_METHOD(startVideo:(RCTPromiseResolveBlock)resolve
                  withRejecter:(RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve([[RCTConvert ZoomVideoSDKErrorValuesReversed] objectForKey: @([[self getVideoHelper] startVideo])]);
    });
}

RCT_EXPORT_METHOD(stopVideo:(RCTPromiseResolveBlock)resolve
                  withRejecter:(RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve([[RCTConvert ZoomVideoSDKErrorValuesReversed] objectForKey: @([[self getVideoHelper] stopVideo])]);
    });
}

RCT_EXPORT_METHOD(rotateMyVideo:(NSNumber *_Nonnull)rotation
                  withResolve:(RCTPromiseResolveBlock)resolve
                  withRejecter:(RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        UIDeviceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        CGFloat rotationDegrees = [rotation floatValue];

        // Normalize the rotation to 0-360 degrees
        rotationDegrees = fmodf(rotationDegrees, 360.0);
        if (rotationDegrees < 0) {
            rotationDegrees += 360.0;
        }

        // Determine the base rotation in degrees based on the current orientation
        CGFloat baseRotation = 0;
        switch (currentOrientation) {
            case UIDeviceOrientationPortrait:
                baseRotation = 0;
                break;
            case UIDeviceOrientationLandscapeRight:
                baseRotation = 90;
                break;
            case UIDeviceOrientationPortraitUpsideDown:
                baseRotation = 180;
                break;
            case UIDeviceOrientationLandscapeLeft:
                baseRotation = 270;
                break;
            default:
                // If the orientation is unknown, assume portrait as a fallback
                baseRotation = 0;
                break;
        }

        // Add the rotation to the base rotation and normalize again
        CGFloat totalRotation = fmodf(baseRotation + rotationDegrees, 360.0);
        UIDeviceOrientation orientation;

        // Determine the new orientation based on the total rotation
        if (totalRotation >= 315 || totalRotation < 45) {
            orientation = UIDeviceOrientationPortrait;
        } else if (totalRotation >= 45 && totalRotation < 135) {
            orientation = UIDeviceOrientationLandscapeRight;
        } else if (totalRotation >= 135 && totalRotation < 225) {
            orientation = UIDeviceOrientationPortraitUpsideDown;
        } else {
            orientation = UIDeviceOrientationLandscapeLeft;
        }
        resolve(@([[self getVideoHelper] rotateMyVideo: orientation]));
    });
}

RCT_EXPORT_METHOD(switchCamera:(NSString *)deviceId
                  withResolve:(RCTPromiseResolveBlock)resolve
                  withRejecter:(RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (deviceId == nil) {
            [[self getVideoHelper] switchCamera];
            resolve(@(YES));
            return;
        }

        if (deviceId.length > 0) {
            resolve(@([[self getVideoHelper] switchCamera:deviceId]));
        } else {
            [[self getVideoHelper] switchCamera];
            resolve(@(YES));
        }
    });
}


RCT_EXPORT_METHOD(isOriginalAspectRatioEnabled: (RCTPromiseResolveBlock)resolve
                  withRejecter:(RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve(@([[self getVideoHelper] isOriginalAspectRatioEnabled]));
    });
}


RCT_EXPORT_METHOD(enableOriginalAspectRatio: (BOOL)enabled
                  withResolver: (RCTPromiseResolveBlock)resolve
                  withRejecter: (RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve(@([[self getVideoHelper] enableOriginalAspectRatio: enabled]));
    });
}

RCT_EXPORT_METHOD(isMyVideoMirrored: (RCTPromiseResolveBlock)resolve
                  withRejecter:(RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve(@([[self getVideoHelper] isMyVideoMirrored]));
    });
}


RCT_EXPORT_METHOD(mirrorMyVideo: (BOOL)enabled
                  withResolver: (RCTPromiseResolveBlock)resolve
                  withRejecter: (RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve([[RCTConvert ZoomVideoSDKErrorValuesReversed] objectForKey: @([[self getVideoHelper] mirrorMyVideo: enabled])]);
    });
}

+ (NSDictionary *)mapCamera: (ZoomVideoSDKCameraDevice*) camera {
    @try {
        return @{
                @"deviceId": camera.deviceId,
                @"deviceName": camera.deviceName,
                @"isSelectDevice": @(camera.isSelectDevice)
        };
    }
    @catch (NSException *e) {
        return @{};
    }
}

+ (NSMutableArray *)mapCameraArray: (NSArray<ZoomVideoSDKCameraDevice *> *)cameraArray {
    NSMutableArray *mappedCameraArray = [NSMutableArray array];

    @try {
        [cameraArray enumerateObjectsUsingBlock:^(ZoomVideoSDKCameraDevice * _Nonnull camera, NSUInteger idx, BOOL * _Nonnull stop) {
            [mappedCameraArray addObject: [RNZoomVideoSdkVideoHelper mapCamera: camera]];
        }];
    }
    @finally {
        return mappedCameraArray;
    }
}

RCT_EXPORT_METHOD(getCameraList: (RCTPromiseResolveBlock)resolve
        withRejecter: (RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve([RNZoomVideoSdkVideoHelper mapCameraArray : [[self getVideoHelper] getCameraDeviceList]]);
    });
}

RCT_EXPORT_METHOD(getNumberOfCameras: (RCTPromiseResolveBlock)resolve
        withRejecter: (RCTPromiseRejectBlock)reject)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        resolve(@([[self getVideoHelper] getCameraDeviceList].count));
    });
}

@end
