
#import "SLAuthorizationManager.h"
#import <Photos/Photos.h>
#import <AVFoundation/AVFoundation.h>
#import <UserNotifications/UserNotifications.h>
// KJ-909 by raohb at 20211224
//#import <Contacts/Contacts.h>
#import <EventKit/EventKit.h>

#define YMSafe_Block(_block_, ...) if (_block_) {_block_(__VA_ARGS__);}

@interface SLAuthorizationManager ()

@end

@implementation SLAuthorizationManager

+ (instancetype)manager {
    static SLAuthorizationManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [SLAuthorizationManager new];
    });
    return manager;
}

+ (YMAuthorizationStatus)authorizationStatusForType:(YMAuthorizationType)type
{
    return [[SLAuthorizationManager manager] _authorizationStatusForType:type];
}

+ (void)requestAuthorization:(YMAuthorizationType)type
                grantedBlock:(void (^)(BOOL))grantedBlock
{
    [[SLAuthorizationManager manager] _requestAuthorization:type grantedBlock:grantedBlock mainThread:NO];
}

+ (void)requestAuthorization:(YMAuthorizationType)type
      mainThreadGrantedBlock:(void (^)(BOOL))grantedBlock
{
    [[SLAuthorizationManager manager] _requestAuthorization:type grantedBlock:grantedBlock mainThread:YES];
}

#pragma mark - private
- (YMAuthorizationStatus)_authorizationStatusForType:(YMAuthorizationType)type
{
    YMAuthorizationStatus status = YMAuthorizationStatusUnknow;
    switch (type) {
        case YMAuthorizationTypePhotoLibrary: {
            status = [self _statusWithSystemStatus:[PHPhotoLibrary authorizationStatus]];
        } break;
            
        case YMAuthorizationTypeCamera: {
            status =  [self _statusWithSystemStatus:[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]];
        } break;
            
        case YMAuthorizationTypeMicrophone: {
            status =  [self _statusWithSystemStatus:[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]];
            
        } break;
            
        case YMAuthorizationTypePush: {
            
            dispatch_semaphore_t signal = dispatch_semaphore_create(0);
            
            __block YMAuthorizationStatus tempStatus = YMAuthorizationStatusUnknow;
            if (@available(iOS 10.0, *)) {
                [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
                    
                    UNAuthorizationStatus unStatus = settings.authorizationStatus;
                    
                    if (@available(iOS 12.0, *)) {
                        if (unStatus == UNAuthorizationStatusProvisional) {
                            tempStatus = YMAuthorizationStatusAuthorized;
                        }
                    }
                    
                    if (unStatus == UNAuthorizationStatusNotDetermined) {
                        tempStatus = YMAuthorizationStatusNotDetermined;
                    }else if (unStatus == UNAuthorizationStatusDenied) {
                        tempStatus = YMAuthorizationStatusDenied;
                    }else if (unStatus == UNAuthorizationStatusAuthorized) {
                        tempStatus = YMAuthorizationStatusAuthorized;
                    }
                    dispatch_semaphore_signal(signal);
                }];
            } else {
                // Fallback on earlier versions
            }
            
            dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
            status = tempStatus;
            
        } break;
            
        case YMAuthorizationTypeCalendar: {
            status =  [self _statusWithSystemStatus:[EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent]];
        } break;
            
        case YMAuthorizationTypeContacts: {
            // KJ-909 by raohb at 20211224
            status = YMAuthorizationStatusDenied;
        } break;
            
        default:
            status =  YMAuthorizationStatusUnknow;
            break;
    }
    return status;
}

- (YMAuthorizationStatus)_statusWithSystemStatus:(NSInteger)status
{
    switch (status) {
        case 0:
            return YMAuthorizationStatusNotDetermined;
            break;
            
        case 1:
        case 2:
            return YMAuthorizationStatusDenied;
            break;
            
        case 3:
        case 4:
            return YMAuthorizationStatusAuthorized;
            break;
            
        default:
            return YMAuthorizationStatusUnknow;
            break;
    }
}

- (void)_requestAuthorization:(YMAuthorizationType)type
                 grantedBlock:(void (^)(BOOL granted))grantedBlock
                   mainThread:(BOOL)isMain
{
    void(^repeatBlock)(BOOL granted) = ^(BOOL granted){
        if (granted) {
            if (isMain) {
                if ([NSThread isMainThread]) {
                    YMSafe_Block(grantedBlock, YES);
                } else {
                    dispatch_sync(dispatch_get_main_queue(), ^{
                        YMSafe_Block(grantedBlock, YES);
                    });
                }
            } else {
                YMSafe_Block(grantedBlock,YES);
            }
        } else {
            if (isMain) {
                if ([NSThread isMainThread]) {
                    YMSafe_Block(grantedBlock, NO);
                } else {
                    dispatch_sync(dispatch_get_main_queue(), ^{
                        YMSafe_Block(grantedBlock, NO);
                    });
                }
            } else {
                YMSafe_Block(grantedBlock,NO);
            }
        }
    };
    
    switch (type) {
        case YMAuthorizationTypePhotoLibrary: {
            [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
                repeatBlock(status == PHAuthorizationStatusAuthorized);
            }];
        } break;
            
        case YMAuthorizationTypeCamera: {
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                repeatBlock(granted);
            }];
        } break;
            
        case YMAuthorizationTypeMicrophone: {
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
                repeatBlock(granted);
            }];
        } break;
            
        case YMAuthorizationTypePush: {
            
            if (@available(iOS 10.0, *)) {
                [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:UNAuthorizationOptionAlert | UNAuthorizationOptionSound |UNAuthorizationOptionBadge completionHandler:^(BOOL granted, NSError * _Nullable error) {
                    repeatBlock(granted);
                }];
            } else {
                // Fallback on earlier versions
            }
            
        } break;
            
        case YMAuthorizationTypeCalendar: {
            [[[EKEventStore alloc] init] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError * _Nullable error) {
                repeatBlock(granted);
            }];
        } break;
            
        case YMAuthorizationTypeContacts: {
            // KJ-909 by raohb at 20211224
            repeatBlock(NO);
        } break;
            
        default:
            break;
    }
}

@end
