//
//  PhobosDataManager.m
//  GMCache
//
//  Created by Locus on 2020/1/21.
//

#import "PhobosDataManager.h"
#import "PhobosSendManager.h"
#import "PhobosConfig.h"
#import "PhobosUtil.h"
#import <MJExtension/MJExtension.h>
#import <mach/mach_time.h>

@implementation PhobosDataManager

static NSManagedObjectContext *PhobosDefaultContext;
static dispatch_semaphore_t phobos_semaphore_t;

+ (void)initialize {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        phobos_semaphore_t = dispatch_semaphore_create(1);
        
        // 创建 NSManagedObjectContext，供埋点库访问CoreData库使用
        PhobosDefaultContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        NSBundle *bundle = [NSBundle bundleForClass:[self class]];
        // 获取埋点数据的实体
        NSURL *modelURL = [bundle URLForResource:@"GMPhobosData" withExtension:@"momd"];
        NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        
        // 创建持久化存储调度器
        NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
        
        // 创建并关联SQLite数据库文件，如果已经存在则不会重复创建
        NSString *dataPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
        dataPath = [dataPath stringByAppendingFormat:@"/%@.sqlite",@"GMPhobos"];
        
        [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:dataPath] options:nil error:nil];
        
        // 设置storeCoordinator
        PhobosDefaultContext.persistentStoreCoordinator = coordinator;
        
        /** 将上次没有获取到发送结果的数据的状态修改为发送失败，待下次重新发送 */
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %d", PhobosDataSendStatusSending];
        NSArray<PhobosSendDataEntity *> *entities = [self fetchDataEntitiesWithPredicate:predicate];
        [self updateDataEntities:entities sendStatus:PhobosDataSendStatusError];
        
        /** 将发送成功的数据删除 */
        NSPredicate *finishPredicate = [NSPredicate predicateWithFormat:@"status = %d", PhobosDataSendStatusFinish];
        NSArray<PhobosSendDataEntity *> *finishEntities = [self fetchDataEntitiesWithPredicate:finishPredicate];
        [self deleteDataEntities:finishEntities];
    });
}

+ (NSArray<PhobosSendDataEntity *> *)fetchToBeSendDataEntities {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %d or status = %d", PhobosDataSendStatusToBeSend, PhobosDataSendStatusError];
    return [self fetchDataEntitiesWithPredicate:predicate];
}

+ (NSArray<PhobosSendDataEntity *> *)fetchDataEntitiesWithPredicate:(NSPredicate *)searchFilter {
    return [PhobosSendDataEntity MR_findAllWithPredicate:searchFilter inContext:PhobosDefaultContext];
}

+ (NSUInteger)fetchCountOfToBeSendEntities {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %d or status = %d", PhobosDataSendStatusToBeSend, PhobosDataSendStatusError];
    return [self fetchCountOfEntitiesWithPredicate:predicate];
}

+ (NSUInteger)fetchCountOfEntitiesWithPredicate:(NSPredicate *)searchFilter {
    return [[PhobosSendDataEntity MR_numberOfEntitiesWithPredicate:searchFilter inContext:PhobosDefaultContext] integerValue];
}

+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI {
    [self insertData:data sendAPI:sendAPI completion:nil];
}

+ (void)insertData:(NSDictionary *)data sendAPI:(NSString *)sendAPI completion:(MRSaveCompletionHandler)completion {
    if (!sendAPI || [sendAPI isEqualToString:@""] || !data) {
        return;
    }
    dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
    PhobosSendDataEntity *entity = [PhobosSendDataEntity MR_createEntityInContext:PhobosDefaultContext];
    entity.data = [data mj_JSONData];
    entity.api = sendAPI;
    entity.status = PhobosDataSendStatusToBeSend;
    entity.id = mach_absolute_time();
    dispatch_semaphore_signal(phobos_semaphore_t);
    [self saveWithCompletion:completion];
}

+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus {
    [self updateDataEntities:entities sendStatus:sendStatus completion:nil];
}

+ (void)updateDataEntities:(NSArray<PhobosSendDataEntity *> *)entities sendStatus:(PhobosDataSendStatus)sendStatus completion:(MRSaveCompletionHandler)completion {
    if (entities.count > 0) {
        dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
        [entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
            obj.status = sendStatus;
        }];
        dispatch_semaphore_signal(phobos_semaphore_t);
        [self saveWithCompletion:completion];
    }
}

+ (void)deleteDataEntities:(NSArray<PhobosSendDataEntity *> *)entities {
    if (entities.count > 0) {
        dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
        [entities enumerateObjectsUsingBlock:^(PhobosSendDataEntity *obj, NSUInteger idx, BOOL * _Nonnull stop) {
            [obj MR_deleteEntityInContext:PhobosDefaultContext];
        }];
        dispatch_semaphore_signal(phobos_semaphore_t);
        [self saveWithCompletion:nil];
    }
}

+ (void)deleteAllEntities {
    dispatch_semaphore_wait(phobos_semaphore_t, DISPATCH_TIME_FOREVER);
    [PhobosSendDataEntity MR_truncateAllInContext:PhobosDefaultContext];
    dispatch_semaphore_signal(phobos_semaphore_t);
    [self saveWithCompletion:nil];
}

/**
 * 在保存完成后调用的完成块。如果发生错误，块将以“BOOL”和“NSError”实例的形式传递成功状态。总是在主队列上调用。
 */
+ (void)saveWithCompletion:(MRSaveCompletionHandler)completion {
    [PhobosDefaultContext MR_saveOnlySelfWithCompletion:completion];
}

@end
