//
//  EZBusinessTool.m
//  EZOpenSDKDemo
//
//  Created by JuneCheng on 2022/2/15.
//  Copyright © 2022 hikvision. All rights reserved.
//

#import "EZBusinessTool.h"
#import <AVFoundation/AVFoundation.h>
#import "EZDeviceInfo.h"
#import "EZCameraInfo.h"
#import "EZSubDeviceInfo.h"
#import "EZDeviceDetailPublicInfo.h"
#import "EZVideoQualityInfo.h"
#import "EZCloudRecordFile.h"
#import "EZDeviceRecordFile.h"
#import "EZPlayer.h"

@implementation EZBusinessTool

#pragma mark - 预览

+ (NSString *)getDeviceQualityTitle:(NSInteger)videoLevel {
    NSString *qualityTitle = NSLocalizedString(@"device_quality_low",@"流畅");
    switch (videoLevel) {
        case 1:
            qualityTitle = NSLocalizedString(@"device_quality_median", @"均衡");
            break;
        case 2:
            qualityTitle = NSLocalizedString(@"device_quality_high", @"高清");
            break;
        case 3:
            qualityTitle = NSLocalizedString(@"device_quality_super", @"超清");
            break;
        case 4:
            qualityTitle = NSLocalizedString(@"device_quality_extreme", @"极清");
            break;
        case 5:
            qualityTitle = NSLocalizedString(@"device_quality_3k", @"3K");
            break;
        case 6:
            qualityTitle = NSLocalizedString(@"device_quality_4k", @"4K");
            break;
            
        default:
            break;
    }
    return qualityTitle;
}

+ (NSInteger)getHigherVideoLevel:(NSInteger)currentVideoLevel deviceDetailPublicInfo:(EZDeviceDetailPublicInfo *)deviceDetailPublicInfo {
    if (deviceDetailPublicInfo && deviceDetailPublicInfo.videoQualityInfos) {
        NSInteger targetVideoLevel = 0;
        NSInteger dif = 100;
        for (int i = 0; i < deviceDetailPublicInfo.videoQualityInfos.count; i ++) {
            EZVideoQualityInfo *videoQualityInfo = deviceDetailPublicInfo.videoQualityInfos[i];
            NSInteger videoLevel = videoQualityInfo.videoLevel;
            // 遍历找出比当前videoLevel大 且 最接近 的清晰度值
            if (videoLevel > currentVideoLevel && videoLevel - currentVideoLevel < dif) {
                targetVideoLevel = videoLevel;
                dif = videoLevel - currentVideoLevel;
            }
        }
        if (targetVideoLevel > 0) {
            return targetVideoLevel;
        }
    }
    
    return currentVideoLevel;
}

+ (NSInteger)getLowerVideoLevel:(NSInteger)currentVideoLevel deviceDetailPublicInfo:(EZDeviceDetailPublicInfo *)deviceDetailPublicInfo {
    if (deviceDetailPublicInfo && deviceDetailPublicInfo.videoQualityInfos) {
        NSInteger targetVideoLevel = 0;
        NSInteger dif = 100;
        for (int i = 0; i < deviceDetailPublicInfo.videoQualityInfos.count; i ++) {
            EZVideoQualityInfo *videoQualityInfo = deviceDetailPublicInfo.videoQualityInfos[i];
            NSInteger videoLevel = videoQualityInfo.videoLevel;
            // 遍历找出比当前videoLevel大 且 最接近 的清晰度值
            if (videoLevel < currentVideoLevel && currentVideoLevel - videoLevel < dif) {
                targetVideoLevel = videoLevel;
                dif = currentVideoLevel - videoLevel;
            }
        }
        if (targetVideoLevel > 0) {
            return targetVideoLevel;
        }
    }
    
    return currentVideoLevel;
}

+ (NSString *)getStreamType:(int)type {
    NSString *streamTypeName = @"";
    switch (type) {
        case 0:
            streamTypeName = @"private_stream";
            break;
        case 1:
            streamTypeName = @"p2p";
            break;
        case 2:
            streamTypeName = @"direct_inner";
            break;
        case 3:
            streamTypeName = @"direct_outer";
            break;
        case 4:
            streamTypeName = @"cloud_playback";
            break;
        case 5:
            streamTypeName = @"cloud_leave_msg";
            break;
        case 6:
            streamTypeName = @"direct_reverse";
            break;
        case 7:
            streamTypeName = @"hcnetsdk";
            break;
        default:
            streamTypeName = [NSString stringWithFormat:@"unknown(%d)", type];
            break;
    }
    return [NSString stringWithFormat:@"stream type: %@", streamTypeName];
}

+ (NSString *)getVideoEncodeType:(int)type {
    NSString *videoEncodeTypeName = @"";
    switch (type) {
        case 0:
            videoEncodeTypeName = @"无编码";
            break;
        case 1:
            videoEncodeTypeName = @"HIK264";
            break;
        case 2:
            videoEncodeTypeName = @"MPEG2";
            break;
        case 3:
            videoEncodeTypeName = @"MPEG4";
            break;
        case 4:
            videoEncodeTypeName = @"MJPEG";
            break;
        case 5:
            videoEncodeTypeName = @"H265";
            break;
        case 6:
            videoEncodeTypeName = @"SVAC";
            break;
        case 256:
            videoEncodeTypeName = @"H264";
            break;
        default:
            videoEncodeTypeName = [NSString stringWithFormat:@"unknown(%d)", type];
            break;
    }
    return videoEncodeTypeName;
}

+ (NSString *)getDecodeType:(int)type {
    NSString *decodeTypeName = @"";
    switch (type) {
        case 1:
            decodeTypeName = @"soft";
            break;
        case 2:
            decodeTypeName = @"hard";
            break;
        default:
            break;
    }
    return decodeTypeName;
}

+ (BOOL)isHubDevice:(NSString *)deviceType {
    if (kStringIsEmpty(deviceType)) {
        return NO;
    }
    if ([@"CASTT" isEqualToString:deviceType] || [@"CAS_HUB_NEW" isEqualToString:deviceType]) {
        return YES;
    }
    return [deviceType startsWith:@"CAS_WG_TEST"];
}

+ (void)checkMicPermissionResult:(void(^)(BOOL enable))retCb {
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
    
    switch (authStatus) {
        case AVAuthorizationStatusNotDetermined:// 未决
        {
            AVAudioSession *avSession = [AVAudioSession sharedInstance];
            [avSession performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
                if (granted) {
                    if (retCb) {
                        retCb(YES);
                    }
                } else {
                    if (retCb) {
                        retCb(NO);
                    }
                }
            }];
        }
            break;
            
        case AVAuthorizationStatusRestricted:// 未授权，家长限制
        case AVAuthorizationStatusDenied:// 未授权
            if (retCb) {
                retCb(NO);
            }
            break;
            
        case AVAuthorizationStatusAuthorized:// 已授权
            if (retCb) {
                retCb(YES);
            }
            break;
            
        default:
            if (retCb) {
                retCb(NO);
            }
            break;
    }
}

+ (void)checkCameraPermissionResult:(void(^)(BOOL enable))retCb {
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    
    switch (authStatus) {
        case AVAuthorizationStatusNotDetermined:// 未决
        {
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                if (granted) {
                    if (retCb) {
                        retCb(YES);
                    }
                } else {
                    if (retCb) {
                        retCb(NO);
                    }
                }
            }];
        }
            break;
            
        case AVAuthorizationStatusRestricted:// 未授权，家长限制
        case AVAuthorizationStatusDenied:// 未授权
            if (retCb) {
                retCb(NO);
            }
            break;
            
        case AVAuthorizationStatusAuthorized:// 已授权
            if (retCb) {
                retCb(YES);
            }
            break;
            
        default:
            if (retCb) {
                retCb(NO);
            }
            break;
    }
}

#pragma mark - 能力集判断

/** 是否支持对讲 */
+ (NSInteger)isSupportTalk:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    // 网关下子设备的能力集挂载在自己的对象上
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportTalk;
    }
    return deviceInfo.isSupportTalk;
}

/** 是否支持云台 */
+ (BOOL)isSupportPTZ:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportPTZ;
    }
    return deviceInfo.isSupportPTZ;
}

/** 是否支持内网直连时倍数设置 */
+ (BOOL)isSupportDirectInnerRelaySpeed:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    // 网关下子设备的能力集挂载在自己的对象上
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportDirectInnerRelaySpeed;
    }
    return deviceInfo.isSupportDirectInnerRelaySpeed;
}

/** 是否支持回放倍率设置 */
+ (BOOL)isSupportPlaybackRate:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportPlaybackRate;
    }
    return deviceInfo.isSupportPlaybackRate;
}

/** 获取回放最大倍速 */
+ (int)getPlaybackMaxSpeed:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.playbackMaxSpeed;
    }
    return deviceInfo.playbackMaxSpeed;
}

/** 是否支持回放慢速(0.5倍、2倍) */
+ (BOOL)isSupportPlaybackSmallSpeed:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportPlaybackSmallSpeed;
    }
    return deviceInfo.isSupportPlaybackSmallSpeed;
}

/** 是否支持SD卡录像封面 */
+ (BOOL)isSupportSdCover:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportSdCover;
    }
    return deviceInfo.isSupportSdCover;
}

/** 是否支持SD卡录像下载 */
+ (BOOL)isSupportSDRecordDownload:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportSDRecordDownload;
    }
    return deviceInfo.isSupportSDRecordDownload;
}

/** 是否支持双目 */
+ (BOOL)isSupportMultiChannel:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportMultiChannel;
    }
    return deviceInfo.isSupportMultiChannel;
}

/** 是否支持自动清晰度 */
+ (BOOL)isSupportDeviceAutoVideolevel:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportDeviceAutoVideolevel;
    }
    return deviceInfo.isSupportDeviceAutoVideolevel;
}

/**
 * 获取设备热点前缀
 * 如果你的定制设备的热点前缀是SoftAP，那么此方法只需要配置EZVIZ和SoftAP即可，不需要配置CAMGO
 *
 * @param deviceHotSpot  0-EZVIZ，1-SoftAP，2-CAMGO
 * @return 设备热点前缀
 */
+ (NSString *)getWiFiConfigPrefix:(NSInteger)deviceHotSpot {
    NSString *WiFiConfigPrefix = @"EZVIZ";
    switch (deviceHotSpot) {
        case 1:
            WiFiConfigPrefix = @"SoftAP";
            break;
        case 2:
            WiFiConfigPrefix = @"CAMGO";
            break;
            
        default:
            break;
    }
    return WiFiConfigPrefix;
}

#pragma mark - 回放倍数工具方法

/** 云录像支持的倍数数组，默认支持 0.5、1、2、4、8、16、32 */
+ (NSArray<NSNumber *> *)getCloudPlaybackRates {
    return @[@(EZOPENSDK_PLAY_RATE_1_2),
             @(EZOPENSDK_PLAY_RATE_1),
             @(EZOPENSDK_PLAY_RATE_2),
             @(EZOPENSDK_PLAY_RATE_4),
             @(EZOPENSDK_PLAY_RATE_8),
             @(EZOPENSDK_PLAY_RATE_16),
             @(EZOPENSDK_PLAY_RATE_32)];
}

/** 云录像支持的倍数显示字符串数组 */
+ (NSArray<NSString *> *)getCloudPlaybackRateStrings {
    return @[@"0.5倍", @"1倍", @"2倍", @"4倍", @"8倍", @"16倍", @"32倍"];
}

/**
 * 获取SD卡录像支持的倍数数组
 * 规则：
 * 1. 先判断设备是否支持倍数回放(isSupportPlaybackRate)
 *    1.1 如果支持，通过 isSupportPlaybackSmallSpeed 和 getPlaybackMaxSpeed 获取支持倍数
 *        1.1.1 isSupportPlaybackSmallSpeed = YES：支持0.5、2倍；= NO：不支持0.5、2倍
 *        1.1.2 getPlaybackMaxSpeed = -1：默认支持1、4、8、16倍；= 1：不支持倍数；= 4：支持1、4；= 8：支持1、4、8；= 16：支持1、4、8、16
 *    1.2 如果不支持，判断是否内网直连(streamFetchType==2) && 支持内网直连倍数(isSupportDirectInnerRelaySpeed)
 *        - 是：返回 1、4、8 倍数
 *        - 否：返回 nil，表示不支持倍数回放
 */
+ (NSArray<NSNumber *> *)getSDCardPlaybackRates:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo streamFetchType:(int)streamFetchType {
    BOOL isSupportPlaybackRate = [self isSupportPlaybackRate:deviceInfo cameraInfo:cameraInfo];
    
    if (isSupportPlaybackRate) {
        // 支持倍数回放，根据能力集组装倍数数组
        NSMutableArray *rates = [NSMutableArray array];
        
        // 1.1.1 判断是否支持慢速(0.5倍和2倍)
        BOOL supportSmallSpeed = [self isSupportPlaybackSmallSpeed:deviceInfo cameraInfo:cameraInfo];
        if (supportSmallSpeed) {
            [rates addObject:@(EZOPENSDK_PLAY_RATE_1_2)];
        }
        
        // 1.1.2 根据 getPlaybackMaxSpeed 获取快速倍数
        int maxSpeed = [self getPlaybackMaxSpeed:deviceInfo cameraInfo:cameraInfo];
        if (maxSpeed == 1) {
            // = 1，不支持倍数，只返回1倍
            [rates addObject:@(EZOPENSDK_PLAY_RATE_1)];
        } else if (maxSpeed == 0) {
            // = 0（原始值-1被转化为0），默认支持1、4、8、16倍
            [rates addObject:@(EZOPENSDK_PLAY_RATE_1)];
            if (supportSmallSpeed) {
                [rates addObject:@(EZOPENSDK_PLAY_RATE_2)];
            }
            [rates addObject:@(EZOPENSDK_PLAY_RATE_4)];
            [rates addObject:@(EZOPENSDK_PLAY_RATE_8)];
            [rates addObject:@(EZOPENSDK_PLAY_RATE_16)];
        } else {
            // 其他值，按maxSpeed判断支持的倍数
            [rates addObject:@(EZOPENSDK_PLAY_RATE_1)];
            if (supportSmallSpeed) {
                [rates addObject:@(EZOPENSDK_PLAY_RATE_2)];
            }
            if (maxSpeed >= 4) {
                [rates addObject:@(EZOPENSDK_PLAY_RATE_4)];
            }
            if (maxSpeed >= 8) {
                [rates addObject:@(EZOPENSDK_PLAY_RATE_8)];
            }
            if (maxSpeed >= 16) {
                [rates addObject:@(EZOPENSDK_PLAY_RATE_16)];
            }
        }
        
        return [rates copy];
    } else {
        // 不支持倍数回放，判断内网直连条件
        BOOL isSupportDirectInnerRelaySpeed = [self isSupportDirectInnerRelaySpeed:deviceInfo cameraInfo:cameraInfo];
        if (streamFetchType == 2 && isSupportDirectInnerRelaySpeed) {
            // 内网直连 && 支持内网直连倍数：返回 1、4、8
            return @[@(EZOPENSDK_PLAY_RATE_1),
                     @(EZOPENSDK_PLAY_RATE_4),
                     @(EZOPENSDK_PLAY_RATE_8)];
        }
        // 不支持倍数回放
        return nil;
    }
}

/** 获取SD卡录像支持的倍数显示字符串数组 */
+ (NSArray<NSString *> *)getSDCardPlaybackRateStrings:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo streamFetchType:(int)streamFetchType {
    NSArray<NSNumber *> *rates = [self getSDCardPlaybackRates:deviceInfo cameraInfo:cameraInfo streamFetchType:streamFetchType];
    if (!rates) {
        return nil;
    }
    NSMutableArray *rateStrings = [NSMutableArray array];
    for (NSNumber *rate in rates) {
        switch (rate.integerValue) {
            case EZOPENSDK_PLAY_RATE_1_2:
                [rateStrings addObject:@"0.5倍"];
                break;
            case EZOPENSDK_PLAY_RATE_1:
                [rateStrings addObject:@"1倍"];
                break;
            case EZOPENSDK_PLAY_RATE_2:
                [rateStrings addObject:@"2倍"];
                break;
            case EZOPENSDK_PLAY_RATE_4:
                [rateStrings addObject:@"4倍"];
                break;
            case EZOPENSDK_PLAY_RATE_8:
                [rateStrings addObject:@"8倍"];
                break;
            case EZOPENSDK_PLAY_RATE_16:
                [rateStrings addObject:@"16倍"];
                break;
            default:
                break;
        }
    }
    return [rateStrings copy];
}

#pragma mark - 回放工具方法

+ (NSDate *)getLatestStopTimeFromCloudRecords:(NSArray<EZCloudRecordFile *> *)records {
    if (!records || records.count == 0) return nil;
    EZCloudRecordFile *firstFile = records.firstObject;
    return firstFile.stopTime;
}

+ (NSDate *)getLatestStopTimeFromDeviceRecords:(NSArray<EZDeviceRecordFile *> *)records {
    if (!records || records.count == 0) return nil;
    EZDeviceRecordFile *firstFile = records.firstObject;
    return firstFile.stopTime;
}

+ (NSUInteger)findCloudRecordIndexByTime:(NSDate *)osdTime records:(NSArray<EZCloudRecordFile *> *)records {
    if (!osdTime || !records || records.count == 0) return NSNotFound;
    for (NSUInteger i = 0; i < records.count; i++) {
        EZCloudRecordFile *file = records[i];
        if ([osdTime compare:file.startTime] != NSOrderedAscending &&
            [osdTime compare:file.stopTime] != NSOrderedDescending) {
            return i;
        }
    }
    return NSNotFound;
}

+ (NSUInteger)findDeviceRecordIndexByTime:(NSDate *)osdTime records:(NSArray<EZDeviceRecordFile *> *)records {
    if (!osdTime || !records || records.count == 0) return NSNotFound;
    for (NSUInteger i = 0; i < records.count; i++) {
        EZDeviceRecordFile *file = records[i];
        if ([osdTime compare:file.startTime] != NSOrderedAscending &&
            [osdTime compare:file.stopTime] != NSOrderedDescending) {
            return i;
        }
    }
    return NSNotFound;
}

#pragma mark - 其他方法

+ (void)judgeRect:(CGRect *)rect {
    CGFloat offsetX = 0;
    CGFloat offsetY = 0;
    if (rect->origin.x < 0) {
        offsetX = ABS(rect->origin.x);
    }
    if (rect->origin.y < 0) {
        offsetY = ABS(rect->origin.y);
    }
    if (rect->origin.x + rect->size.width > 1.0) {
        offsetX = 1.0 - rect->origin.x - rect->size.width;
    }
    if (rect->origin.y + rect->size.height > 1.0) {
        offsetY = 1.0 - rect->origin.y - rect->size.height;
    }
    rect->origin.x += offsetX;
    rect->origin.y += offsetY;
}

@end
