//
//  KLTDatabaseHandler.m
//  KaiLiTe
//
//  Created by boosal on 2016/9/13.
//  Copyright © 2016年 boosal. All rights reserved.
//

#import "KLTDatabaseHandler.h"
#import "KLTFormat.h"
#import "CGMAlgo.h"
#import "KLTCommonDefine.h"
#import "KLTAppDelegate.h"
#import "NSString+KLTDateString.h"
#import <Foundation/Foundation.h>
#import "KLTPrefixHeader.pch"
#import "KLTBluetoothManager.h"
@implementation KLTDatabaseHandler

- (instancetype)init {
    self = [super init];
    if (self) {
        KLTAppDelegate *appDelegateInstance = [[KLTAppDelegate alloc] init];
        //KLTAppDelegate *delegate = (KLTAppDelegate *)UIApplication.sharedApplication.delegate;
        self.appDelegate = appDelegateInstance;
        self.context = appDelegateInstance.managedObjectContext;
    }
    return self;
}

+ (KLTDatabaseHandler *)shared {
    static KLTDatabaseHandler *handler;
    static dispatch_once_t onceToken;

    // IMPORTANT:
    // CoreData context in this SDK is NSMainQueueConcurrencyType.
    // If `shared` is first initialized from a background queue, CoreBluetooth can later call
    // `willRestoreState` on the main queue and block waiting on dispatch_once, producing an ANR.
    // Force initialization to happen on the main thread to avoid dispatch_once contention/deadlock.
    if ([NSThread isMainThread]) {
        dispatch_once(&onceToken, ^{
            handler = [[self alloc] init];
        });
    } else {
        dispatch_sync(dispatch_get_main_queue(), ^{
            dispatch_once(&onceToken, ^{
                handler = [[self alloc] init];
            });
        });
    }
    return handler;
}

- (void)updatePOCAlgoBeforeRef:(ReceiveData *)data {
    NSDate *receiveDate = [NSString getDateTimeWithString:data.receiveDateTime];
    
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDateComponents *comp = [calendar components: NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute fromDate:receiveDate];
    float algo_k = [[User_Defaults objectForKey:@"algo_k"] floatValue];
    float algo_r = [[User_Defaults objectForKey:@"algo_r"] floatValue];
    NSString *localName = data.device.advertise.localName;
    
    LatestData *d = [[LatestData alloc] initWithParameters:[data.glucoseId intValue] andIw:[data.operatingCurrent floatValue] andIb:[data.blankCurrent floatValue] andT:[data.temperature floatValue] andK0:algo_k andR:algo_r andDay:(int)[comp day] andHour:(int)[comp hour] andMinute:(int)[comp minute] andName:localName];
    d.algorithm = AlgorithmType_CT4;
    
    KLTLog(@"算法入参dataId=%@, operatingCurrent=%@, blankCurrent=%@, temperature=%@, algo_k=%@, algo_r=%@, day=%@, hour=%@, minute=%@, localName=%@, algorithm=%@", @(d.glucoseId), @(d.Iw), @(d.Ib), @(d.T), @(d.K0), @(d.R), @(d.day), @(d.hour), @(d.minute), d.name, @(d.algorithm));
    CurrentGlucose *currentGlucose = [AlgorithmTools algorithmLatestGlucose:d];
    
    /* data.glu 保存 ADC 算法结果 单位mmol/L */
    /* data.gluADC 保存 凯立特 算法结果 单位mg/dL */
    data.glu = @(currentGlucose.GluMG/18.0);
    data.gluADC = @(currentGlucose.GluMG);
    data.calibration = @(currentGlucose.BGMG);
    data.error = @(currentGlucose.errorCode);
    data.trend = @(currentGlucose.trend);
    data.countdownDays = @(currentGlucose.countdownDays);
    data.countdownHours = @(currentGlucose.countdownHours);
    data.countdownMinutes = @(currentGlucose.countdownMinutes);
    
    // [Notification_Center postNotificationName:@"ErrorStatusFromTransmitter" object:data];
    [self.appDelegate saveContext];
}

// 从发射器接收到的数据
- (ReceiveData *)addReceiveCT3DataWithDevice:(Device *)currentDevice {
    ReceiveData *receive = [NSEntityDescription insertNewObjectForEntityForName:@"ReceiveDataInfo" inManagedObjectContext:self.context];
    receive.userBG = currentDevice.userBG;
    receive.initialBeginDate = currentDevice.initialBeginDate;
    
    [self.appDelegate saveContext];
    return receive;
}

// 保存发射器信息
- (Device *)addDevice:(CBPeripheral *)peripheral {
    Device *de = [self queryDeviceWithId:peripheral.identifier.UUIDString];
    if (de) {
        [self updateDeviceWithDeviceId:de.identifier scannedTime:[KLTFormat getDateString] connectTime:nil disConnectTime:nil];
        return de;
    }
    
    Device *device = [NSEntityDescription insertNewObjectForEntityForName:@"Device" inManagedObjectContext:self.context];
    device.deviceName = peripheral.name;
    device.connectedDateTime = nil;
    device.scannedTime = [KLTFormat getDateString];
    device.identifier = [peripheral.identifier UUIDString];
    [self.appDelegate saveContext];
    
    return device;
}

// 保存advertisement 数据
- (Advertise *)addAdvertisement:(NSDictionary *)ad {
    NSArray *ads = [self queryTableWithName:@"Advertise"];
    for (Advertise *advertise in ads) {
        if ([advertise.localName isEqualToString:ad[@"kCBAdvDataLocalName"]] && [advertise.manufactureData isEqualToString:[KLTFormat dataToHexString:ad[@"kCBAdvDataManufacturerData"] isReverse:NO]]) {
            [self.context deleteObject:advertise];
            [self.appDelegate saveContext];
        }
    }
    
    Advertise *advertise = [NSEntityDescription insertNewObjectForEntityForName:@"Advertise" inManagedObjectContext:self.context];
    advertise.isConnectable = ad[@"kCBAdvDataIsConnectable"];
    advertise.localName = ad[@"kCBAdvDataLocalName"];
    advertise.manufactureData = [KLTFormat dataToHexString:ad[@"kCBAdvDataManufacturerData"] isReverse:NO];
    
    advertise.txPowerLevel = ad[@"kCBAdvDataTxPowerLevel"];
    advertise.advertiseDateTime = [KLTFormat getDateString];
    [self.appDelegate saveContext];
    
    return advertise;
}

// ------------- 保存血糖数据 -------------
//Save blood glucose data
- (GlucoseData *)addCT3GlucoseDataWithReceiveData:(ReceiveData *)data {
    GlucoseData *glucose = [NSEntityDescription insertNewObjectForEntityForName:@"GlucoseData" inManagedObjectContext:self.context];
    glucose.userBG = data.userBG;
    glucose.dataId = data.glucoseId;
    glucose.device = data.device;
    glucose.isDelete = 0;
    
    glucose.receiveDateTime = [NSString stringWithFormat:@"%@-%02d-%02d %02d:%02d",data.year,[data.month intValue],[data.day intValue],[data.hour intValue],[data.minute intValue]];
    glucose.initialBeginDate = data.device.initialBeginDate;
    glucose.operatingCurrent = data.operatingCurrent;
    glucose.blankCurrent = data.blankCurrent;
    glucose.temperature = data.temperature;
    float algo_k = [[User_Defaults objectForKey:@"algo_k"] floatValue];
    float algo_r = [[User_Defaults objectForKey:@"algo_r"] floatValue];
    
    LatestData *d = nil;
    NSString *localName = data.device.advertise.localName;
    int userBG = roundf(glucose.userBG.floatValue * 18);
    if (userBG > 0) {
        d = [[LatestData alloc] initWithParameters:glucose.dataId.intValue andIw:[glucose.operatingCurrent floatValue] andIb:[glucose.blankCurrent floatValue] andT:[glucose.temperature floatValue] andK0:algo_k andR:algo_r andDay:[data.day intValue] andHour:[data.hour intValue] andMinute:[data.minute intValue] andNewBgToGlucoseId:glucose.dataId.intValue andNewBgValue:userBG andName:localName];
    } else {
        d = [[LatestData alloc] initWithParameters:([glucose.dataId intValue]) andIw:[glucose.operatingCurrent floatValue] andIb:[glucose.blankCurrent floatValue] andT:[glucose.temperature floatValue] andK0:algo_k andR:algo_r andDay:[data.day intValue] andHour:[data.hour intValue] andMinute:[data.minute intValue] andName:localName];
    }
    d.algorithm = AlgorithmType_CT4;
    
    KLTLog(@"算法入参dataId=%@, operatingCurrent=%@, blankCurrent=%@, temperature=%@, algo_k=%@, algo_r=%@, day=%@, hour=%@, minute=%@, localName=%@, newBgValue=%@, algorithm=%@", @(d.glucoseId), @(d.Iw), @(d.Ib), @(d.T), @(d.K0), @(d.R), @(d.day), @(d.hour), @(d.minute), d.name, @(d.newBgValue), @(d.algorithm));
    CurrentGlucose *currentGlucose = [AlgorithmTools algorithmLatestGlucose:d];
    
    if (currentGlucose.errorCode == ERROR_CODE_ALGORITHM_DATA) {
        [self reloadQueryHistoryData:YES];
        
        if (userBG > 0) {
            d = [[LatestData alloc] initWithParameters:glucose.dataId.intValue andIw:[glucose.operatingCurrent floatValue] andIb:[glucose.blankCurrent floatValue] andT:[glucose.temperature floatValue] andK0:algo_k andR:algo_r andDay:[data.day intValue] andHour:[data.hour intValue] andMinute:[data.minute intValue] andNewBgToGlucoseId:glucose.dataId.intValue andNewBgValue:userBG andName:localName];
        } else {
            d = [[LatestData alloc] initWithParameters:([glucose.dataId intValue]) andIw:[glucose.operatingCurrent floatValue] andIb:[glucose.blankCurrent floatValue] andT:[glucose.temperature floatValue] andK0:algo_k andR:algo_r andDay:[data.day intValue] andHour:[data.hour intValue] andMinute:[data.minute intValue] andName:localName];
        }
        d.algorithm = AlgorithmType_CT4;
        
        KLTLog(@"ERROR_CODE_ALGORITHM_DATA:dataId=%@, operatingCurrent=%@, blankCurrent=%@, temperature=%@, algo_k=%@, algo_r=%@, day=%@, hour=%@, minute=%@, localName=%@, newBgValue=%@, algorithm=%@", @(d.glucoseId), @(d.Iw), @(d.Ib), @(d.T), @(d.K0), @(d.R), @(d.day), @(d.hour), @(d.minute), d.name, @(d.newBgValue), @(d.algorithm));
        currentGlucose = [AlgorithmTools algorithmLatestGlucose:d];
        NSString *logString = [NSString stringWithFormat:@"glucoseId=%@, Iw=%@, Ib=%@, T=%@,dayCount=%@, hour=%@, minute=%@, milles=%@, GluMG=%@,BGCount=%@, BGICount=%@, errorCode=%@  trend=%@  calibrationStatus=%@,  countdownDays=%@, countdownHours=%@, countdownMinutes=%@ ",
                    @(d.glucoseId),
                    @(d.Iw),
                    @(d.Ib),
                    @(d.T),
                    @(d.day),
                    @(d.hour),
                    @(d.minute),
                    @(d.timeMillis),
                    @(currentGlucose.GluMG),
                    @(currentGlucose.BGCount),
                    @(currentGlucose.BGICount),
                    @(currentGlucose.errorCode),
                    @(currentGlucose.trend),
                    @(currentGlucose.BGMG),
                    @(currentGlucose.countdownDays),
                    @(currentGlucose.countdownHours),
                    @(currentGlucose.countdownHours)
                                       
                ];
                KLTRunLog *runLog = [KLTAppDelegate getCurrentKLTRunLog];
                [runLog useCurrentCSV:localName];
                KLTRunWarn(logString);
    }
    
    glucose.errorCode = @(currentGlucose.errorCode);
    glucose.trend = @(currentGlucose.trend);
    /* glucose.glu 保存 ADC 算法结果 单位mmol */
    /* glucose.gluADC 保存 凯立特 算法结果 单位mg/dL */
    glucose.glu = @(currentGlucose.GluMG/18.0);
    glucose.gluADC = @(currentGlucose.GluMG);
    // 标识下次能不能再输入校准参比
    glucose.calibrationStatus = @(currentGlucose.calibrationStatus);
    
    data.glu = @(currentGlucose.GluMG/18.0);
    data.gluADC = @(currentGlucose.GluMG);
    data.calibration = @(currentGlucose.BGMG);
    data.error = @(currentGlucose.errorCode);
    data.trend = @(currentGlucose.trend);
    data.countdownDays = @(currentGlucose.countdownDays);
    data.countdownHours = @(currentGlucose.countdownHours);
    data.countdownMinutes = @(currentGlucose.countdownMinutes);
    
    glucose.countdownDays = @(currentGlucose.countdownDays);
    glucose.countdownHours = @(currentGlucose.countdownHours);
    glucose.countdownMinutes = @(currentGlucose.countdownMinutes);
    glucose.year = data.year;
    glucose.glucoseId = data.glucoseId;
    glucose.month = data.month;
    glucose.day = data.day;
    glucose.minute = data.minute;
    glucose.hour = data.hour;
    glucose.error = data.error;
    
    //  [Notification_Center postNotificationName:@"ErrorStatusFromTransmitter" object: glucose];
    [Notification_Center postNotificationName:@"CheckErrorStatusFromLastBatchData" object: glucose];
    NSString *logString = [NSString stringWithFormat:@"glucoseId=%@, Iw=%@, Ib=%@, T=%@,dayCount=%@, hour=%@, minute=%@, milles=%@, GluMG=%@,BGCount=%@, BGICount=%@, errorCode=%@  trend=%@  calibrationStatus=%@,  countdownDays=%@, countdownHours=%@, countdownMinutes=%@ ",
                @(d.glucoseId),
                @(d.Iw),
                @(d.Ib),
                @(d.T),
                @(d.day),
                @(d.hour),
                @(d.minute),
                @(d.timeMillis),
                @(currentGlucose.GluMG),
                @(currentGlucose.BGCount),
                @(currentGlucose.BGICount),
                @(currentGlucose.errorCode),
                @(currentGlucose.trend),
                @(currentGlucose.BGMG),
                @(currentGlucose.countdownDays),
                @(currentGlucose.countdownHours),
                @(currentGlucose.countdownHours)
                                   
            ];
            KLTRunLog *runLog = [KLTAppDelegate getCurrentKLTRunLog];
            [runLog useCurrentCSV:localName];
            KLTRunWarn(logString);
    [self.appDelegate saveContext];
    return glucose;
}

- (BOOL)hasDeviceData {
    NSManagedObjectContext *context = self.context;
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Device"];
    
    // We're only interested in knowing if there's at least one record
    [fetchRequest setFetchLimit:1];

    NSError *error = nil;
    NSUInteger count = [context countForFetchRequest:fetchRequest error:&error];

    if (error) {
        NSLog(@"Error fetching Device data: %@", error.localizedDescription);
        return NO;
    }

    return count > 0;
}

// 查询某一张表name
- (NSArray *)queryTableWithName:(NSString *)name {
    NSEntityDescription *entity = [NSEntityDescription entityForName:name inManagedObjectContext:self.context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    request.entity = entity;
    
    return [self.context executeFetchRequest:request error:nil];
}


//- (NSArray<GlucoseData*> *)queryGlucoseDataWithDevice:(Device *)currentDevice {
//    NSEntityDescription *entity = [NSEntityDescription entityForName:@"GlucoseData" inManagedObjectContext:self.context];
//    NSFetchRequest *request = [[NSFetchRequest alloc] init];
//    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"device.identifier = %@ AND initialBeginDate = %@", currentDevice.identifier, currentDevice.initialBeginDate];
//    request.entity = entity;
//    request.predicate = predicate;
//    NSArray *resendDatas = [self.context executeFetchRequest:request error:nil];
//    resendDatas = [resendDatas sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"receiveDateTime" ascending:YES]]];
//    return resendDatas;
//}

- (NSArray<GlucoseData*> *)queryGlucoseDataWithDevice:(Device *)currentDevice {
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"GlucoseData" inManagedObjectContext:self.context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"device.identifier = %@ AND initialBeginDate = %@", currentDevice.identifier, currentDevice.initialBeginDate];
    request.entity = entity;
    request.predicate = predicate;
    
    NSArray *resendDatas = [self.context executeFetchRequest:request error:nil];
    resendDatas = [resendDatas sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"receiveDateTime" ascending:YES]]];
    
    // 🖨️ Add single-line logging for each GlucoseData entry
    NSLog(@"==== GlucoseData (Fetched %lu records) for Device: %@ ====", (unsigned long)resendDatas.count, currentDevice.identifier);
    for (GlucoseData *g in resendDatas) {
        NSLog(@"[ID:%@] Date:%@ | glu:%@ mmol/L | gluADC:%@ mg/dL | BG:%@ | T:%@°C | Ib:%@ | Iw:%@ | Trend:%@ | Err:%@ | CalStatus:%@ | countdownMinut:%@ | countdownHours:%@ | countdownDays:%@" ,
              g.dataId,
              g.receiveDateTime,
              g.glu,
              g.gluADC,
              g.userBG,
              g.temperature,
              g.blankCurrent,
              g.operatingCurrent,
              g.trend,
              g.errorCode,
              g.calibrationStatus,
              g.countdownMinutes,
              g.countdownHours,
              g.countdownDays
              
              );
    }
    
    return resendDatas;
}

// 如果不是第一次连接发射器，更新device连接次数和连接时间
- (void)updateDeviceWithDeviceId:(NSString *)identify
                     scannedTime:(NSString *)scannedTime
                     connectTime:(NSString *)connectTime
                  disConnectTime:(NSString *)disconnectTime {
    NSArray * devices = [self queryTableWithName:@"Device"];
    for (Device *de in devices) {
        if ([de.identifier isEqualToString:identify]) {
            if (scannedTime) {
                de.scannedTime = scannedTime;
            }
            if (connectTime) {
                de.connectedDateTime = connectTime;
            }
            if (disconnectTime) {
                de.disconnectedDateTime = disconnectTime;
            }
            break;
        }
    }
    [self.appDelegate saveContext];
}

- (void)updateDevice:(Device *)currentDevice
    initialBeginDate:(NSString *)beginTime
             endDate:(NSString *)endTime {
    if (beginTime) {
        currentDevice.initialBeginDate = beginTime;
    }
    if (endTime) {
        currentDevice.initialEndDate = endTime;
    }
    
    [self.appDelegate saveContext];
}

- (void)deleteSQLiteDataArray {
    [self.appDelegate deleteAllCoreData];
}

- (void)deleteReceiveDataArray:(NSArray *)dataArray {
    
    for (NSManagedObject *record in dataArray) {
        // Example update – update a timestamp or reset isDeleted flag
        [record setValue:@(1) forKey:@"isDelete"]; // uncomment if you want to undelete
        //[record setValue:[NSDate date] forKey:@"updatedAt"]; // or any other change
    }
    [self.appDelegate saveContext];
    /*
    for (NSManagedObject *object in dataArray) {
        [self.context deleteObject:object];
    }

    NSError *error = nil;
    if (![self.context save:&error]) {
        NSLog(@"Failed to delete specific ReceiveDataInfo: %@", error);
    } else {
        NSLog(@"Successfully deleted specific ReceiveDataInfo records.");
        [self.appDelegate saveContext];
    }*/
}

// 根据条件查询Receivedata表

//- (NSArray *)queryReceiveDataWithDevice:(Device *)currentDevice needUserBG:(BOOL)needUserBG {
//    if (!self.context) {
//        NSLog(@"Core Data context is nil");
//        return @[];
//    }
//
//    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ReceiveDataInfo" inManagedObjectContext:self.context];
//    if (!entity) {
//        NSLog(@"Entity 'ReceiveDataInfo' not found in Core Data model");
//        return @[];
//    }
//
//    NSFetchRequest *request = [[NSFetchRequest alloc] init];
//    request.entity = entity;
//
//    NSPredicate *predicate;
//    if (needUserBG) {
//        predicate = [NSPredicate predicateWithFormat:@"device.identifier = %@ AND initialBeginDate = %@ AND gluADC > 0 AND gluADC != nil AND isDelete == nil", currentDevice.identifier, currentDevice.initialBeginDate];
//    } else {
//        predicate = [NSPredicate predicateWithFormat:@"device.identifier = %@ AND initialBeginDate = %@ AND isDelete == nil", currentDevice.identifier, currentDevice.initialBeginDate];
//    }
//    request.predicate = predicate;
//
//    NSError *fetchError = nil;
//    NSArray *resendDatas = [self.context executeFetchRequest:request error:&fetchError];
//
//    if (fetchError) {
//        NSLog(@"❌ Fetch error: %@", fetchError.localizedDescription);
//        return @[];
//    }
//
//    resendDatas = [resendDatas sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"receiveDateTime" ascending:YES]]];
//    NSLog(@"📡 resendDatas: %@", resendDatas);
//
//    return resendDatas;
//}

- (NSArray *)queryReceiveDataWithDevice:(Device *)currentDevice needUserBG:(BOOL)needUserBG {
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ReceiveDataInfo" inManagedObjectContext:self.context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSPredicate *predicate;
    if (needUserBG) {
        predicate = [NSPredicate predicateWithFormat:@"device.identifier = %@ AND initialBeginDate = %@ && userBG > 0 && userBG != NIL",currentDevice.identifier, currentDevice.initialBeginDate];
    } else {
        predicate = [NSPredicate predicateWithFormat:@"device.identifier = %@ AND initialBeginDate = %@",currentDevice.identifier, currentDevice.initialBeginDate];
    }
    request.entity = entity;
    request.predicate = predicate;
    NSArray *resendDatas = [self.context executeFetchRequest:request error:nil];
    resendDatas = [resendDatas sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"receiveDateTime" ascending:YES]]];
    return resendDatas;
}

- (NSArray *)queryAllReceiveData {
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ReceiveDataInfo" inManagedObjectContext:self.context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    request.entity = entity;

    // No predicate — fetch all
    NSArray *allData = [self.context executeFetchRequest:request error:nil];

    // Sort by receiveDateTime ascending
    allData = [allData sortedArrayUsingDescriptors:@[
        [NSSortDescriptor sortDescriptorWithKey:@"receiveDateTime" ascending:YES]
    ]];
    return allData;
}

// 根据设备id查询设备
- (Device *)queryDeviceWithId:(NSString *)deviceID {
    NSArray *allDevices = [self queryTableWithName:@"Device"];
    Device *currentDevice;
    for (Device *device in allDevices) {
        if ([device.identifier isEqualToString:deviceID]) {
            currentDevice = device;
            break;
        }
    }
    return currentDevice;
}

// 查询最近连接过的一个设备是否是断开状态
- (Device *)isLatestDeviceDisconnected {
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Device" inManagedObjectContext:self.context];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    request.entity = entity;
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"initialBeginDate != nil AND initialBeginDate.length != 0"];
    request.predicate = predicate;
    
    NSArray *array = [self.context executeFetchRequest:request error:nil];
    array = [array sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"connectedDateTime" ascending:NO]]];
    if (array && array.count > 0) {
        Device *device = (Device *)[array firstObject];
        return device;
    }
    return nil;
}

// 查询最近一次连接的最大的血糖ID
//Query the highest glucose ID from the most recent connection.
- (NSInteger)getLatestAndMaxGlucoseIdOfDevice:(Device *)currentDevice {
    NSArray *array = [self queryReceiveDataWithDevice:currentDevice needUserBG:NO];
    if (array.count > 0) {
        ReceiveData *data = [array lastObject];
        return data ? [data.glucoseId integerValue] : -1;
    }
    return -1;
}

// 获取距离某个设备的到期时间还剩多少数据没有接收完
//Get how much data remains to be received before the device reaches its expiration time
- (NSInteger)numberOfLifeCycleSensorWithDevice:(Device *)currentDevice endNumber:(int)endNumber {
    if (currentDevice) {
        NSArray *array = [self queryReceiveDataWithDevice:currentDevice needUserBG:NO];
        return endNumber - array.count;
    }
    return endNumber;
}



#pragma mark - APP重启后需要手动调用历史数据

- (void)reloadQueryHistoryData:(BOOL)calculateError2Data {
    Device *currentDevice = KLTBluetoothManager.sharedManager.currentDevice;
    if (nil == currentDevice) {
        return;
    }
    NSArray<ReceiveData*> *arrayFromInitial = [self queryReceiveDataWithDevice:currentDevice needUserBG:NO];
    if (0 == arrayFromInitial.count) {
        return;
    }
    if (calculateError2Data && arrayFromInitial.count > 1) {
        arrayFromInitial = [arrayFromInitial subarrayWithRange:NSMakeRange(0, arrayFromInitial.count-1)];
    }
    float *Iws = nil;
    float *Ibs = nil;
    float *Ts = nil;
    int *bgToGlucoseIds = nil;
    int *bgValues = nil;
    HistoryData *data = [[HistoryData alloc] init];
    unsigned long index = 0;
    Iws =  malloc(sizeof(float) * arrayFromInitial.count);
    Ibs = malloc(sizeof(float) * arrayFromInitial.count);
    Ts = malloc(sizeof(float) * arrayFromInitial.count);
    for (ReceiveData *receive in arrayFromInitial) {
        index = [receive.glucoseId intValue];
        Iws[index] = [receive.operatingCurrent floatValue];
        Ibs[index] = [receive.blankCurrent floatValue];
        Ts[index] = [receive.temperature floatValue];
    }
 
    ReceiveData *firstData = arrayFromInitial.firstObject;
    NSDate *receiveDate = [NSString getDateTimeWithString:firstData.receiveDateTime];
    NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDateComponents *comp = [calendar components: NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute fromDate:receiveDate];
    data.startDay = (int)[comp day];     // 开始初始化的日期，日
    data.startHour = (int)[comp hour];     // 开始初始化的日期，小时
    data.startMinute = (int)[comp minute];  // 开始初始化的日期，分钟
 
    data.glucoseId = (int)index;
    data.Iws = Iws;
    data.IwsCount = (int)index + 1;
    data.Ibs = Ibs;
    data.IbsCount = (int)index + 1;
    data.Ts = Ts;
    data.TsCount = (int)index + 1;
    
    // 校准后的点
    //Point after calibration
    NSArray<ReceiveData*> *needUserBgs = [self queryReceiveDataWithDevice:currentDevice needUserBG:YES];
    NSUInteger numberOfUserBgs = needUserBgs.count;
    if (needUserBgs.count > 0) {
        bgToGlucoseIds = malloc(sizeof(int) * numberOfUserBgs);
        bgValues = malloc(sizeof(int) * numberOfUserBgs);
        for (int i = 0; i < numberOfUserBgs; i++) {
            ReceiveData *receiveModel = needUserBgs[i];
            bgToGlucoseIds[i] = receiveModel.glucoseId.intValue;
            bgValues[i] = roundf(receiveModel.userBG.floatValue * 18);
            KLTLog(@"newBgToGlucoseIds: bgToGlucoseIds=%@, userBG=%@", receiveModel.glucoseId, receiveModel.userBG);
        }
        data.newBgToGlucoseIds = bgToGlucoseIds;
        data.newBgToGlucoseIdsCount = (int)numberOfUserBgs;
        data.newBgValues = bgValues;
        data.newBgValuesCount = (int)numberOfUserBgs;
    }
    
    [data setTransmitterName:currentDevice.advertise.localName];
    float algo_k = [[User_Defaults objectForKey:@"algo_k"] floatValue];
    float algo_r = [[User_Defaults objectForKey:@"algo_r"] floatValue];
    data.K0 = algo_k;
    data.R = algo_r;
 
    CurrentGlucose *currentGlucose = [AlgorithmTools algorithmGlucose:data];
    KLTLog(@"rerunADCAlgo: algorithm=%@, currentGlucose.errorCode = %@", @(data.algorithm), @(currentGlucose.errorCode));
    if (Iws != nil) {
        free(Iws);
        Iws = nil;
    }
    if (Ibs != nil) {
        free(Ibs);
        Ibs = nil;
    }
    if (Ts != nil) {
        free(Ts);
        Ts = nil;
    }
    if (bgToGlucoseIds != nil) {
        free(bgToGlucoseIds);
        bgToGlucoseIds = nil;
    }
    if (bgValues != nil) {
        free(bgValues);
        bgValues = nil;
    }
}

 
- (void)handleReceiveDataForError2Data {
 
    Device *currentDevice = KLTBluetoothManager.sharedManager.currentDevice;
 
    if (!currentDevice) {
        NSLog(@"handleReceiveDataForError2Data: no currentDevice");
        return;
    }
 
    if (currentDevice.identifier.length == 0 ||
        currentDevice.initialBeginDate.length == 0) {
        NSLog(@"handleReceiveDataForError2Data: missing identifier or initialBeginDate");
        return;
    }
 
    NSManagedObjectContext *context = self.context;
    NSError *error = nil;
 
    // STEP 1: find first ReceiveData with error == 2
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    request.entity = [NSEntityDescription entityForName:@"ReceiveDataInfo"
                                 inManagedObjectContext:context];
 
    NSPredicate *errorPredicate =
    [NSPredicate predicateWithFormat:
     @"device.identifier = %@ AND initialBeginDate = %@ AND error = 2",
     currentDevice.identifier,
     currentDevice.initialBeginDate];
 
    request.predicate = errorPredicate;
    request.sortDescriptors =
    @[[NSSortDescriptor sortDescriptorWithKey:@"glucoseId" ascending:YES]];
 
    NSArray<ReceiveData *> *errorDatas =
    [context executeFetchRequest:request error:&error];
 
    if (error) {
        NSLog(@"handleReceiveDataForError2Data fetch error: %@", error);
        return;
    }
 
    if (errorDatas.count == 0) {
        NSLog(@"handleReceiveDataForError2Data: no error=2 records");
        return;
    }
 
    ReceiveData *firstErrorData = errorDatas.firstObject;
 
    NSLog(@"First error2 packet glucoseId=%@", firstErrorData.glucoseId);
 
    // STEP 2: delete ReceiveData >= first error packet
    NSFetchRequest *deleteRequest = [[NSFetchRequest alloc] init];
    deleteRequest.entity =
    [NSEntityDescription entityForName:@"ReceiveDataInfo"
                inManagedObjectContext:context];
 
    NSPredicate *deletePredicate =
    [NSPredicate predicateWithFormat:
     @"device.identifier = %@ AND initialBeginDate = %@ AND glucoseId >= %@",
     currentDevice.identifier,
     currentDevice.initialBeginDate,
     firstErrorData.glucoseId];
 
    deleteRequest.predicate = deletePredicate;
 
    NSArray<ReceiveData *> *toDelete =
    [context executeFetchRequest:deleteRequest error:&error];
 
    if (error) {
        NSLog(@"handleReceiveDataForError2Data delete fetch error: %@", error);
        return;
    }
 
    for (ReceiveData *obj in toDelete) {
        [context deleteObject:obj];
    }
 
    [self.appDelegate saveContext];
 
    NSLog(@"handleReceiveDataForError2Data: deleted %lu ReceiveData packets",
          (unsigned long)toDelete.count);
}
 
//After restarting the app, is it necessary to manually request historical data?
// - (void)reloadQueryHistoryData {
//     Device *currentDevice = KLTBluetoothManager.sharedManager.currentDevice;
//     if (nil == currentDevice) {
//         return;
//     }
//     NSArray<ReceiveData*> *arrayFromInitial = [self queryReceiveDataWithDevice:currentDevice needUserBG:NO];
//     if (0 == arrayFromInitial.count) {
//         return;
//     }
//     float *Iws = nil;
//     float *Ibs = nil;
//     float *Ts = nil;
//     int *bgToGlucoseIds = nil;
//     int *bgValues = nil;
//     HistoryData *data = [[HistoryData alloc] init];
//     unsigned long index = 0;
//     Iws =  malloc(sizeof(float) * arrayFromInitial.count);
//     Ibs = malloc(sizeof(float) * arrayFromInitial.count);
//     Ts = malloc(sizeof(float) * arrayFromInitial.count);
//     for (ReceiveData *receive in arrayFromInitial) {
//         index = [receive.glucoseId intValue];
//         Iws[index] = [receive.operatingCurrent floatValue];
//         Ibs[index] = [receive.blankCurrent floatValue];
//         Ts[index] = [receive.temperature floatValue];
//     }

//     ReceiveData *firstData = arrayFromInitial.firstObject;
//     NSDate *receiveDate = [NSString getDateTimeWithString:firstData.receiveDateTime];
//     NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
//     NSDateComponents *comp = [calendar components: NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute fromDate:receiveDate];
//     data.startDay = (int)[comp day];     // 开始初始化的日期，日
//     data.startHour = (int)[comp hour];     // 开始初始化的日期，小时
//     data.startMinute = (int)[comp minute];  // 开始初始化的日期，分钟

//     data.glucoseId = (int)index;
//     data.Iws = Iws;
//     data.IwsCount = (int)index + 1;
//     data.Ibs = Ibs;
//     data.IbsCount = (int)index + 1;
//     data.Ts = Ts;
//     data.TsCount = (int)index + 1;
    
//     // 校准后的点
//     //Point after calibration
//     NSArray<ReceiveData*> *needUserBgs = [self queryReceiveDataWithDevice:currentDevice needUserBG:YES];
//     NSUInteger numberOfUserBgs = needUserBgs.count;
//     if (needUserBgs.count > 0) {
//         bgToGlucoseIds = malloc(sizeof(int) * numberOfUserBgs);
//         bgValues = malloc(sizeof(int) * numberOfUserBgs);
//         for (int i = 0; i < numberOfUserBgs; i++) {
//             ReceiveData *receiveModel = needUserBgs[i];
//             bgToGlucoseIds[i] = receiveModel.glucoseId.intValue;
//             bgValues[i] = roundf(receiveModel.userBG.floatValue * 18);
//             KLTLog(@"newBgToGlucoseIds: bgToGlucoseIds=%@, userBG=%@", receiveModel.glucoseId, receiveModel.userBG);
//         }
//         data.newBgToGlucoseIds = bgToGlucoseIds;
//         data.newBgToGlucoseIdsCount = (int)numberOfUserBgs;
//         data.newBgValues = bgValues;
//         data.newBgValuesCount = (int)numberOfUserBgs;
//     }
    
//     [data setTransmitterName:currentDevice.advertise.localName];
//     float algo_k = [[User_Defaults objectForKey:@"algo_k"] floatValue];
//     float algo_r = [[User_Defaults objectForKey:@"algo_r"] floatValue];
//     data.K0 = algo_k;
//     data.R = algo_r;

//     CurrentGlucose *currentGlucose = [AlgorithmTools algorithmGlucose:data];
//     KLTLog(@"rerunADCAlgo: algorithm=%@, currentGlucose.errorCode = %@", @(data.algorithm), @(currentGlucose.errorCode));
//     if (Iws != nil) {
//         free(Iws);
//         Iws = nil;
//     }
//     if (Ibs != nil) {
//         free(Ibs);
//         Ibs = nil;
//     }
//     if (Ts != nil) {
//         free(Ts);
//         Ts = nil;
//     }
//     if (bgToGlucoseIds != nil) {
//         free(bgToGlucoseIds);
//         bgToGlucoseIds = nil;
//     }
//     if (bgValues != nil) {
//         free(bgValues);
//         bgValues = nil;
//     }
// }

@end
