//
//  AAILivenessUtil.m
//  AAILivenessDemo
//
//  Created by Advance.ai on 2019/3/2.
//  Copyright © 2019 Advance.ai. All rights reserved.
//

#import "AAILivenessUtil.h"
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>

@interface AAILivenessUtil()
@property(nonatomic, assign) float volume;
@property(nonatomic, strong) AVAudioPlayer *audioPlayer;
@property(nonatomic, strong) NSOperationQueue *brightnessQueue;
@property(nonatomic, assign) CGFloat currBrightness;
@property(nonatomic, strong) MPVolumeView *volumeView;
@end

@implementation AAILivenessUtil

- (instancetype)init
{
    self = [super init];
    if (self) {
        _volume = 0.5;
        _brightnessQueue = [[NSOperationQueue alloc] init];
        _brightnessQueue.maxConcurrentOperationCount = 1;
        [self configSystemVolume:0.5];
    }
    return self;
}

+ (BOOL)isSilent
{
    return [AVAudioSession sharedInstance].outputVolume == 0;
}

- (MPVolumeView *)createVolumeView
{
    if (_volumeView == nil) {
        // Try keep MPVolumeView out of visible area
        MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 5, 5)];
        
        // Find an available window and add MPVolumeView on it.
        if (@available(iOS 13.0, *)) {
            NSSet<UIScene *> *winsSet = [UIApplication sharedApplication].connectedScenes;
            for (UIScene *scene in winsSet) {
                if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) {
                    UIWindowScene *winScene = (UIWindowScene *)scene;
                    for (UIWindow *wd in winScene.windows) {
                        if (wd.isKeyWindow) {
                            [wd addSubview:volumeView];
                            break;
                        }
                    }
                    break;
                }
            }
        } else {
            // Fallback on earlier versions
            NSArray<UIWindow *> *winds = [UIApplication sharedApplication].windows;
            for (UIWindow *wd in winds) {
                if (wd.isKeyWindow) {
                    [wd addSubview:volumeView];
                    break;
                }
            }
        }
        
        _volumeView = volumeView;
    }
    
    return _volumeView;
}

- (UISlider*)volumeSlider
{
    UISlider *slider =nil;
    MPVolumeView *volumeView = [self createVolumeView];
    volumeView.showsVolumeSlider = YES;
    for(UIView *view in volumeView.subviews) {
        if ([view.class.description isEqualToString:@"MPVolumeSlider"]) {
            slider = (UISlider*)view;
            break;
        }
    }
    return slider;
}

- (void)configSystemVolume:(float)volume
{
    UISlider *slider = [self volumeSlider];
    [slider setValue:volume animated:NO];
    [slider sendActionsForControlEvents:UIControlEventTouchUpInside];
    [_volumeView sizeToFit];
}

- (void)configPlayerVolume:(float)volume
{
    _volume = volume;
    if (_audioPlayer) {
        _audioPlayer.volume = volume;
    }
}

- (void)configVolume:(float)volume
{
    _volume = volume;
    [self configSystemVolume:volume];
}

- (void)removeVolumeView
{
    if (_volumeView) {
        [_volumeView removeFromSuperview];
        _volumeView = nil;
    }
}

- (void)setVolume:(float)volume
{
    _volume = volume;
    if (_audioPlayer) {
        _audioPlayer.volume = volume;
    }
}

+ (NSString *)currLanguageKey
{
    NSArray *array = [NSLocale preferredLanguages];
    if (array.count >= 1) {
        NSString *lanKey = [array objectAtIndex:0];
        NSArray *components = [lanKey componentsSeparatedByString:@"-"];
        if (components.count == 2) {
            lanKey = components.firstObject;
        } else if (components.count == 3) {
            if ([lanKey hasPrefix:@"zh-Hans"]) {
                lanKey = @"zh-Hans";
            }
        }
        
        return lanKey;
    }
    
    return @"en";
}

+ (NSString *)currLanguage
{
    NSArray *availableLprojItems = @[@"en", @"id", @"vi", @"zh-Hans", @"th", @"es", @"ms", @"hi", @"fil"];
    NSString *currLproj = [self currLanguageKey];
    for (NSString *item in availableLprojItems) {
        if ([item isEqualToString:currLproj]) {
            return currLproj;
        }
    }
    return @"en";
}

- (void)playAudio:(NSString *)audioName
{
    [self playAudio:audioName lprojName:nil];
}

- (NSString *)audioPath:(NSString *)audioName lprojName:(NSString * _Nullable)lprojName basePath:(NSString *)basePath
{
    NSString *audioBundlePath = [basePath stringByAppendingPathComponent:@"/AAIAudio.bundle"];
    NSString *lan = [[self class] currLanguage];
    if (lprojName != nil) {
        lan = lprojName;
    }
    return [NSString stringWithFormat:@"%@/%@.lproj/%@",audioBundlePath, lan, audioName];
}

- (void)playAudio:(NSString *)audioName lprojName:(NSString * _Nullable)lprojName
{
    if (!audioName) return;
    
    // Try to load a customized audio file from the main bundle.
    // If not found, fall back to the default resource bundle.
    NSString *path = [self audioPath:audioName lprojName:lprojName basePath:NSBundle.mainBundle.bundlePath];
    if(![[NSFileManager defaultManager] fileExistsAtPath:path]) {
        path = [self audioPath:audioName lprojName:lprojName basePath:[AAILivenessUtil resourceBundle].bundlePath];
    }
    
    // Just return if the audio file doesn't exist
    if(![[NSFileManager defaultManager] fileExistsAtPath:path]) {
        return;
    }
    
    NSURL *url = [NSURL URLWithString:path];
    NSError *error = NULL;
    
    AVAudioPlayer *player = _audioPlayer;
    if (player) {
        [player stop];
    }
    
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    player.volume = _volume;
    _audioPlayer = player;
    if (!error) {
        [player play];
    }
}

+ (NSString *)localStrForKey:(NSString *)key
{
    return [self localStrForKey:key lprojName:nil];
}

+ (NSString *)localStrForKey:(NSString *)key lprojName:(NSString * _Nullable)lprojName
{
    NSString *first = lprojName != nil ? lprojName : [NSLocale preferredLanguages].firstObject;
    NSArray<NSString *> *splits = [first componentsSeparatedByString:@"-"];
    NSString *mainBundlePath = [NSBundle mainBundle].bundlePath;
    
    for (NSInteger i = splits.count - 1; i >= 0; i--) {
        NSString *code = [[splits subarrayWithRange:NSMakeRange(0, i + 1)] componentsJoinedByString:@"-"];
        NSString *lprojPath = [NSString stringWithFormat:@"%@/%@.lproj", mainBundlePath, code];
        NSBundle *lprojBundle = [NSBundle bundleWithPath:lprojPath];
        if (lprojBundle == nil) {
            continue;
        }
        
        NSString *str = [lprojBundle localizedStringForKey:key value:@"404" table:@"AAILiveness"];
        if (![str isEqualToString:@"404"]) {
            return str;
        }
    }
    
    NSString *lan = (lprojName == nil) ? [self currLanguage] : lprojName;
    NSString *languageStringPath = [self languageStringBundlePath];
    NSString *lprojPath =  [NSString stringWithFormat:@"%@/%@.lproj",languageStringPath, lan];
    NSString *str = [[NSBundle bundleWithPath:lprojPath] localizedStringForKey:key value:nil table:nil];
    if (str == nil) {
        str = @"";
    }
    return str;
}

+ (UIImage * _Nullable)imgWithName:(NSString *)imgName
{
    NSBundle *bundle = [self resourceBundle];
    UIImage *img = [UIImage imageNamed:imgName inBundle:bundle compatibleWithTraitCollection:nil];
    return img;
}

+ (NSArray<UIImage *> * _Nullable)stateImgWithType:(AAILivenessStage)detectionType
{
    switch (detectionType) {
        case AAILivenessStageBlink: {
            NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:4];
            for (int i = 1; i <= 4; i++) {
                UIImage *img = [AAILivenessUtil imgWithName:[NSString stringWithFormat:@"blink_%d",i]];
                if (img != nil) {
                    [array addObject:img];
                }
            }
            return array;
        }
        case AAILivenessStageMouth: {
            NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:4];
            for (int i = 1; i <= 5; i++) {
                UIImage *img = [AAILivenessUtil imgWithName:[NSString stringWithFormat:@"open_mouth_%d",i]];
                if (img != nil) {
                    [array addObject:img];
                }
            }
            return array;
        }
        case AAILivenessStagePosYaw: {
            NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:4];
            for (int i = 1; i <= 4; i++) {
                UIImage *img = [AAILivenessUtil imgWithName:[NSString stringWithFormat:@"turn_head_%d",i]];
                if (img != nil) {
                    [array addObject:img];
                }
            }
            return array;
        }
        default:
            break;
    }
    
    return nil;
}

#pragma mark - brightless

- (void)saveCurrBrightness
{
    _currBrightness = [UIScreen mainScreen].brightness;
}

- (void)graduallySetBrightness:(CGFloat)value
{
    [_brightnessQueue cancelAllOperations];
    
    CGFloat ratio = 0.01;
    CGFloat brightness = [UIScreen mainScreen].brightness;
    CGFloat step = ratio * ((value > brightness) ? 1 : -1);
    int times = fabs((value - brightness) / ratio);
    
    for (CGFloat i = 1; i < times + 1; i++) {
        [_brightnessQueue addOperationWithBlock:^{
            [NSThread sleepForTimeInterval:1 / 180.0];
            dispatch_async(dispatch_get_main_queue(), ^{
                [UIScreen mainScreen].brightness = brightness + i * step;
            });
        }];
    }
}

- (void)graduallyResumeBrightness
{
    [self graduallySetBrightness:_currBrightness];
}

- (void)fastResumeBrightness
{
    [_brightnessQueue cancelAllOperations];
    __weak typeof(self) weakSelf = self;
    [_brightnessQueue addOperationWithBlock:^{
        if (weakSelf) {
            [UIScreen mainScreen].brightness = weakSelf.currBrightness;
        }
    }];
}

#pragma mark - bundle

+ (NSBundle *)currentBundle {
#ifdef SWIFTPM_MODULE_BUNDLE
    return SWIFTPM_MODULE_BUNDLE;
#else
    return [NSBundle bundleForClass:[self class]];
#endif
}

+ (NSBundle *)resourceBundle {
    // Pod integration case
    NSBundle *bundle = [NSBundle bundleWithPath:[[self currentBundle] pathForResource:@"AAILivenessResources" ofType:@"bundle"]];
    if (!bundle) {
        // Manually integration case
        bundle = [self currentBundle];
    }
    return bundle;
}

+ (NSString *)modelBundlePath {
    return [[self resourceBundle].bundlePath stringByAppendingString:@"/AAIModel.bundle"];
}

+ (NSString *)languageStringBundlePath {
    return [[self resourceBundle].bundlePath stringByAppendingString:@"/AAILanguageString.bundle"];
}

+ (NSString *)audioBundlePath {
    return [[self resourceBundle].bundlePath stringByAppendingString:@"/AAIAudio.bundle"];
}

@end
