//
//  DDTimerManager.m
//  DDToolsKit_Private
//  Created by DDIsFriend on 2022/7/29.

#import "DDTimerManager.h"

typedef NSString * DDTimerManagerOperate NS_STRING_ENUM;

DDTimerManagerOperate const DDTimerManagerOperateAddSuccess = @"定时器添加成功";
DDTimerManagerOperate const DDTimerManagerOperateAddErrorOfContained = @"定时器添加失败,原因:已添加";
DDTimerManagerOperate const DDTimerManagerOperateRemoveSuccess = @"定时器移除成功";
DDTimerManagerOperate const DDTimerManagerOperateRemoveErrorOfNotContained = @"定时器移除失败,原因:未包含";
DDTimerManagerOperate const DDTimerManagerOperateTimerNotFind = @"未找到定时器";

@interface DDTimerManager ()
@property (nonatomic, strong)NSPointerArray *timers;
@property (nonatomic, strong)dispatch_queue_t timerManagerQueue;
@end

@implementation DDTimerManager
+ (instancetype)dd_shareManager{
    static DDTimerManager *_manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _manager = [[self alloc] initWithSuper];
    });
    return _manager;
}

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

- (instancetype)init{
    @throw [NSException exceptionWithName:NSGenericException reason:@"init unavailable, use 'dd_shareManager' instead" userInfo:nil];
    return nil;
}

- (void)dd_addTimerWithName:(NSString *)timerName timeInterval:(NSTimeInterval)timeInterval repeatCount:(NSUInteger)repeatCount delay:(NSTimeInterval)delayTimeInterval timerBlock:(nullable void(^)(DDTimerManager * _timerManager,DDTimerObject *_Nullable timerObject, NSUInteger timerObjectIndex))timerBlock completionBlock:(nullable void(^)(void))completionBlock{
    dispatch_async(self.timerManagerQueue, ^{
        BOOL addSuccess = [self dd_addTimerWithName:timerName timeInterval:timeInterval repeatCount:repeatCount delay:delayTimeInterval timerBlock:timerBlock];
        if (addSuccess) {
            @try {
                if (completionBlock) {
                    completionBlock();
                }
            } @catch (NSException *exception) {
                NSLog(@"%@",exception);
            } @finally {
                
            }
        }else{
            NSLog(@"name = ’%@‘ , %@",timerName,DDTimerManagerOperateAddErrorOfContained);
        }
    });
}

- (BOOL)dd_addTimerWithName:(NSString *)timerName timeInterval:(NSTimeInterval)timeInterval repeatCount:(NSUInteger)repeatCount delay:(NSTimeInterval)delayTimeInterval timerBlock:(nullable void(^)(DDTimerManager * _timerManager,DDTimerObject *_Nullable timerObject, NSUInteger timerObjectIndex))timerBlock{
    __block BOOL addTimerSuccess = NO;
    __block BOOL isAddedSameNameTimerBefore = NO;
    
    [self.timers.allObjects enumerateObjectsUsingBlock:^(DDTimerObject *_Nonnull timerObject, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([timerObject.name isEqualToString:timerName]) {
            isAddedSameNameTimerBefore = YES;
            *stop = YES;
        }
    }];
    
    if (isAddedSameNameTimerBefore) {
        NSLog(@"name = '%@' , %@",timerName,DDTimerManagerOperateAddErrorOfContained);
        addTimerSuccess = NO;
        return addTimerSuccess;
    }
    __weak typeof(self) weakSelf = self;
    DDTimerObject *timerObject = [DDTimerObject dd_timerObjectWithName:timerName timeInterval:timeInterval repeatCount:repeatCount timerBlock:^(DDTimerObject * _Nullable timerObject) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (timerBlock) {
            timerBlock(strongSelf,timerObject,strongSelf.timers.count);
        }
    } completionHandler:^(DDTimerObject * _Nullable timerObject) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        /// timer will be removed when action completed.
        [strongSelf dd_removeTimerNamed:timerObject.name];
    }];
    
    [self.timers addPointer:(__bridge void * _Nullable)timerObject];
    
    NSLog(@"name = '%@' , %@",timerObject.name,DDTimerManagerOperateAddSuccess);
    
    /// make timer activate.
    dispatch_after(dispatch_time((delayTimeInterval == TIME_FOREVER) ? DISPATCH_TIME_FOREVER : DISPATCH_TIME_NOW, (int64_t)(delayTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [timerObject dd_activateTimerObject];
    });
    
    addTimerSuccess = YES;
    return addTimerSuccess;
}

- (DDTimerRunState)dd_runStateAboutTimerObjectNamed:(NSString *)timerName{
    DDTimerObject *_timerObject = nil;

    for (DDTimerObject *timerObject in self.timers.allObjects){
        if ([timerObject.name isEqualToString:timerName]) {
            _timerObject = timerObject;
            break;
        }
    }
    if (_timerObject == nil) {
        NSLog(@"name = ’%@‘ , %@",timerName,DDTimerManagerOperateTimerNotFind);
        return NO;
    }
    
    return _timerObject.runState;
}

- (BOOL)dd_containTimerNamed:(NSString *)timerName{
    BOOL isAddedSameNameTimerBefore = NO;

    for (DDTimerObject *timerObject in self.timers.allObjects){
        if ([timerObject.name isEqualToString:timerName]) {
            isAddedSameNameTimerBefore = YES;
            break;
        }
    }

    return isAddedSameNameTimerBefore;
}

- (void)dd_makeTimerActivateNamed:(NSString *)timerName{
    DDTimerObject *_timerObject;
    for (DDTimerObject *timerObject in self.timers.allObjects){
        if ([timerObject.name isEqualToString:timerName]) {
            _timerObject = timerObject;
            break;
        }
    }
    if (_timerObject != nil) {
        [_timerObject dd_activateTimerObject];
    }else{
        NSLog(@"name = ’%@‘ , %@",timerName,DDTimerManagerOperateTimerNotFind);
    }
}

- (void)dd_makeTimerSuspendNamed:(NSString *)timerName{
    DDTimerObject *_timerObject;
    for (DDTimerObject *timerObject in self.timers.allObjects){
        if ([timerObject.name isEqualToString:timerName]) {
            _timerObject = timerObject;
            break;
        }
    }
    if (_timerObject != nil) {
        [_timerObject dd_suspendTimerObject];
    }else{
        NSLog(@"name = ’%@‘ , %@",timerName,DDTimerManagerOperateTimerNotFind);
    }
}

- (void)dd_makeTimerResumeNamed:(NSString *)timerName{

    DDTimerObject *_timerObject;
    for (DDTimerObject *timerObject in self.timers.allObjects){
        if ([timerObject.name isEqualToString:timerName]) {
            _timerObject = timerObject;
            break;
        }
    }

    if (_timerObject != nil) {
        [_timerObject dd_resumeTimerObject];
    }else{
        NSLog(@"name = ’%@‘ , %@",timerName,DDTimerManagerOperateTimerNotFind);
    }

}

- (void)dd_removeTimer:(DDTimerObject *)timerObject{
    dispatch_async(self.timerManagerQueue, ^{
        [self removeTimerWithTimerObject:timerObject timerName:nil];
    });
}

- (void)dd_removeTimerNamed:(NSString *)timerName{
    dispatch_async(self.timerManagerQueue, ^{
        [self removeTimerWithTimerObject:nil timerName:timerName];
    });
}

- (void)removeTimerWithTimerObject:(nullable DDTimerObject *)timerObject timerName:(nullable NSString *)timerName{
    ///if timerObject is non-nulable, timerName is invalid.
    if (self.timers == 0) return;

    NSMutableArray *removeIndexs = [NSMutableArray array];
    [self.timers.allObjects enumerateObjectsUsingBlock:^(DDTimerObject *_Nonnull _timerObject, NSUInteger idx, BOOL * _Nonnull stop) {
        if ((timerObject != nil && timerObject == _timerObject) || (timerName != nil && [timerName isEqualToString:_timerObject.name])) {
            [removeIndexs addObject:@(idx)];
            *stop = YES;
        }
    }];
    
    if (removeIndexs.count > 0) {
        
        for (NSNumber *indexNum in removeIndexs){
            DDTimerObject *timerObject = [self.timers pointerAtIndex:[indexNum integerValue]];
            [timerObject dd_cancelTimerObject];
            [self.timers removePointerAtIndex:[indexNum integerValue]];
            timerObject = nil;
        }
        
        if (timerName != nil) {
            NSLog(@"name = '%@' , %@",timerName,DDTimerManagerOperateRemoveSuccess);
        }
        
        [self logLeftTimer];
        
    }else{
        if (timerObject != nil) {
            NSLog(@"timerObject = %@ , %@",timerObject,DDTimerManagerOperateRemoveErrorOfNotContained);
        }else if (timerName != nil){
            NSLog(@"name = %@ , %@",timerName,DDTimerManagerOperateRemoveErrorOfNotContained);
        }
        
    }
    
    [removeIndexs removeAllObjects];
    removeIndexs = nil;
}

- (void)dd_removeAllTimer{
    if (self.timers.count == 0) return;
    
    dispatch_async(self.timerManagerQueue, ^{
        NSUInteger timersCount = self.timers.count;
        
        for (NSUInteger i = 0; i < timersCount; i++) {
            @autoreleasepool {
                DDTimerObject *timerObject = [self.timers pointerAtIndex:i];
                [timerObject dd_cancelTimerObject];
                [self.timers replacePointerAtIndex:i withPointer:NULL];
                timerObject = nil;
            }
        }
        [self.timers compact];

        [self logLeftTimer];
    });

}

- (void)logLeftTimer{
    if (self.timers.count == 0) return NSLog(@"DDTimerManager剩余定时器数量为0");
    [self.timers.allObjects enumerateObjectsUsingBlock:^(DDTimerObject *_Nonnull _timerObject, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"当前剩余的定时器name = %@",_timerObject.name);
    }];
}

#pragma mark -- <lazy>
- (NSPointerArray *)timers{
    if (!_timers) {
        _timers = [NSPointerArray strongObjectsPointerArray];
    }
    return _timers;
}

- (dispatch_queue_t)timerManagerQueue{
    if (!_timerManagerQueue) {
        _timerManagerQueue = dispatch_queue_create("timerManager_timerManagerQueue", DISPATCH_QUEUE_SERIAL);
    }
    return _timerManagerQueue;
}
@end
