#import "AviationInterruptionBroadcaster.h"

@implementation AviationInterruptionBroadcaster

static NSMutableDictionary<NSNumber *, AviationInterruptionBlock> *sObservers = nil;
static NSLock *sLock = nil;
static unsigned long long sNextToken = 1;

+ (void)initialize {
    if (self == [AviationInterruptionBroadcaster class]) {
        sObservers = [NSMutableDictionary dictionary];
        sLock = [[NSLock alloc] init];
    }
}

+ (void)installSessionObserver {
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        [[NSNotificationCenter defaultCenter]
            addObserverForName:AVAudioSessionInterruptionNotification
                        object:[AVAudioSession sharedInstance]
                         queue:[NSOperationQueue mainQueue]
                    usingBlock:^(NSNotification *notification) {
                        [AviationInterruptionBroadcaster handleNotification:notification];
                    }];
    });
}

+ (nullable NSNumber *)addObserver:(AviationInterruptionBlock)block {
    if (block == nil) {
        return nil;
    }

    [sLock lock];
    NSNumber *token = @(sNextToken++);
    sObservers[token] = [block copy];
    [sLock unlock];

    [self installSessionObserver];
    return token;
}

+ (void)removeObserver:(nullable NSNumber *)token {
    if (token == nil) {
        return;
    }
    [sLock lock];
    [sObservers removeObjectForKey:token];
    [sLock unlock];
}

+ (void)handleNotification:(NSNotification *)notification {
    NSNumber *typeValue = notification.userInfo[AVAudioSessionInterruptionTypeKey];
    if (typeValue == nil) {
        return;
    }

    AVAudioSessionInterruptionType type =
        (AVAudioSessionInterruptionType)typeValue.unsignedIntegerValue;
    if (type != AVAudioSessionInterruptionTypeBegan &&
        type != AVAudioSessionInterruptionTypeEnded) {
        return;
    }

    BOOL began = type == AVAudioSessionInterruptionTypeBegan;
    BOOL shouldResume = NO;
    if (!began) {
        NSNumber *options = notification.userInfo[AVAudioSessionInterruptionOptionKey];
        shouldResume = options != nil &&
            (options.unsignedIntegerValue & AVAudioSessionInterruptionOptionShouldResume) != 0;
    }

    [sLock lock];
    NSArray<AviationInterruptionBlock> *snapshot = sObservers.allValues;
    [sLock unlock];

    for (AviationInterruptionBlock block in snapshot) {
        block(began, shouldResume);
    }
}

@end
