//
//  GMScreenRecorderManager.m
//  LJRepayer
//
//  Created by 刘鹿杰 on 2019/7/30.
//  Copyright © 2019 刘鹿杰. All rights reserved.
//

#import "GMScreenRecorderManager.h"
#import "RPPreviewViewController+MovieURL.h"
#import <Photos/Photos.h>
#import "GMHudModule+Alpha.h"

static GMScreenRecorderManager *sharedManager = nil;

@interface GMScreenRecorderManager()<RPScreenRecorderDelegate>

@property (assign, nonatomic) BOOL isRecord;

@end


@implementation GMScreenRecorderManager

// 初始化方法
- (instancetype)init{
    if (self = [super init]) {
        _isRecord = NO;
        [RPScreenRecorder sharedRecorder].delegate = self;
    }
    return self;
}

// 单例创建对象
+ (instancetype)sharedManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedManager = [[GMScreenRecorderManager alloc] init];
    });
    return sharedManager;
}

// 开始录屏
+ (BOOL)startRecord:(BOOL)isNeedMicroPhone suscess:(StartRecordSuccess)suscess {
    return [[self sharedManager] start:isNeedMicroPhone suscess:suscess];
}

// 结束录屏，并保存视频到相册
+ (void)stopRecordWithSave{
    [[self sharedManager] stopAndSave];
}

// 结束录屏，丢弃这次的录制
+ (void)stopRecordWithDiscard{
    [[self sharedManager] stopRecord];
}

// 是否正在录制视频
- (BOOL)isRecording {
    if (RPScreenRecorder.sharedRecorder.isRecording || [self isRecord]) { // 正在录制 Or 或者硬件不可以用
        [self showStartRecordErrorWithText:@"正在录屏中，请稍后再试!"];
        return NO;
    }
    return YES;
}

// 检验设备是否支持 ReplayKit
- (BOOL)replayKitIsAvailable {
    if(!RPScreenRecorder.sharedRecorder.isAvailable) {
        [self showStartRecordErrorWithText:@"当前设备不支持录屏功能，请升级您的系统版本!"];
        return NO;
    }
    return YES;
}

// 开始录制
- (BOOL)start:(BOOL)isNeedMicroPhone suscess:(StartRecordSuccess)suscess {
    __weak typeof(self) weakSelf = self;
    if ([self isRecording] && [self replayKitIsAvailable]) {
        if (@available(iOS 10.2, *)) {
            RPScreenRecorder.sharedRecorder.microphoneEnabled = NO;
            [RPScreenRecorder.sharedRecorder startRecordingWithHandler:^(NSError * _Nullable error) {
                if (!error) {
                    weakSelf.isRecord = YES;
                    dispatch_async(dispatch_get_main_queue(), ^{
                        suscess();
                    });
                }else{
                    weakSelf.isRecord = NO;
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [weakSelf showStartRecordErrorWithText:@"录屏开启失败,请重启手机后再试！"];
                    });
                }
            }];
        }else{
            [self showStartRecordErrorWithText:@"系统版本过低，录屏未能成功开启！"];
        }
    }
    return YES;
}

// 结束录屏，丢弃这次的录制
-(void)stopRecord {
    __weak typeof(self) weakSelf = self;
    if (RPScreenRecorder.sharedRecorder.isRecording) {
        [[RPScreenRecorder sharedRecorder] stopRecordingWithHandler:^(RPPreviewViewController * _Nullable previewViewController, NSError * _Nullable error) {
            weakSelf.isRecord = NO;
            if (!error) {
                [[RPScreenRecorder sharedRecorder] discardRecordingWithHandler:^{}];
            }
        }];
    }
}

// 结束录屏，并保存视频到相册
-(void)stopAndSave {
    __weak typeof(self) weakSelf = self;
    if (RPScreenRecorder.sharedRecorder.isRecording) {
        [[RPScreenRecorder sharedRecorder] stopRecordingWithHandler:^(RPPreviewViewController * _Nullable previewViewController, NSError * _Nullable error) {
            weakSelf.isRecord = NO;
            if (!error) {
                if ([previewViewController respondsToSelector:@selector(movieURL)]) {
                    NSURL *videoURL = [previewViewController.movieURL copy];
                    if (videoURL) {
                        dispatch_async(dispatch_get_main_queue(), ^{
                            [[GMScreenRecorderManager sharedManager] mixAudioAndVidoWithInputURL2:videoURL outPath:[weakSelf getVidoesPathStr]];
                        });
                    }
                }else{
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [weakSelf showWarningWithText:@"获取不到视频连接，请升级手机系统后再试一次！"];
                    });
                }
            }else{
                dispatch_async(dispatch_get_main_queue(), ^{
                    [weakSelf showWarningWithText:@"停止录屏失败，请您重启手机再试！"];
                });
            }
        }];
    }else{
        [weakSelf showWarningWithText:@"录屏期间退出屏幕，录制文件已经被丢弃！"];
    }
}

// 获取输出路经
-(NSString *)getVidoesPathStr{
    NSDate* date = [NSDate dateWithTimeIntervalSinceNow:0];
    NSTimeInterval time = [date timeIntervalSince1970] * 1000;
    NSString *timeString = [NSString stringWithFormat:@"%.0f", time];
    NSString *fileName = [NSString stringWithFormat:@"%@_%@",@"tmp",timeString];
    NSString *outPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[fileName stringByAppendingString:@".mp4"]];
    return outPath;
}

+ (BOOL)detectionPhotoState:(void(^)(void))authorizedResultBlock {
    BOOL isAvalible = NO;
    PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus];
    if (authStatus == PHAuthorizationStatusNotDetermined) {
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            
            if (status == PHAuthorizationStatusAuthorized)
            {
                if (authorizedResultBlock)
                {
                    authorizedResultBlock();
                }
            }}];
    } else if (authStatus == PHAuthorizationStatusAuthorized) {
        isAvalible = YES;
        if (authorizedResultBlock)
        {
            authorizedResultBlock();
        }
    } else
    {
        NSLog(@"没有相册权限");
    }
    return isAvalible;
}

#pragma mark - RPScreenRecordDelegate 暂时未用这个方法
-(void)screenRecorder:(RPScreenRecorder *)screenRecorder didStopRecordingWithPreviewViewController:(RPPreviewViewController *)previewViewController error:(NSError *)error{
    NSLog(@"%@",error);
}

- (void)screenRecorderDidChangeAvailability:(RPScreenRecorder *)screenRecorder {
    //如果变成了无法录屏，应该发送通知去停止录屏
    NSLog(@"屏幕录制的能力改变了 %d %d",screenRecorder.isRecording,screenRecorder.isAvailable);
}

#pragma mark 判断取出的视频文件是不是在规定时间之内录制的
- (BOOL)videoTimeCheck:(NSDate *)videoDate {
    if (!videoDate) {
        //特殊情况备注
        return YES;
    }
    //判断是否在5分钟之内录制
    BOOL timeOK = [GMScreenRecorderManager getTimeChange:videoDate];
    return timeOK;
}

+ (BOOL)getTimeChange:(NSDate *)time {
    NSDate *currentTimeDate = [NSDate date];    //  现在时间
    NSDate *getTimeDate = time;
    // 现在时间 与 获取时间 之差
    long dd = (long)[currentTimeDate timeIntervalSince1970] - [getTimeDate timeIntervalSince1970];
    
    BOOL timeOK = NO;
    // 1小时内。。
    if (dd/3600<1){
        if (dd/60 <= 2) {
            timeOK = YES;
        }else{
            timeOK = NO;
        }
    }
    return timeOK;
}

// 合成视频
- (void)mixAudioAndVidoWithInputURL2:(NSURL*)inputURL outPath:(NSString *)outPath {
    //视频 声音 来源
    NSURL *videoInputUrl = inputURL;
    NSURL *audioInputUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"ios音乐" ofType:@"mp3"]];
    //合成之后的输出路径
    NSString *outPutPath = outPath;
    //混合后的视频输出路径
    NSURL *outPutUrl = [NSURL fileURLWithPath:outPutPath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:outPutPath])
    {
        [[NSFileManager defaultManager] removeItemAtPath:outPutPath error:nil];
    }
    
    //时间起点
    CMTime nextClistartTime = kCMTimeZero;
    //创建可变的音视频组合
    AVMutableComposition *comosition = [AVMutableComposition composition];
    
    //视频采集
    NSDictionary *options = @{AVURLAssetPreferPreciseDurationAndTimingKey:@YES};
    AVURLAsset * videoAsset = [[AVURLAsset alloc] initWithURL:videoInputUrl options:options];
    //视频时间范围
    CMTimeRange videoTimeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration);
    // 视频通道 枚举 kCMPersistentTrackID_Invalid = 0
    AVMutableCompositionTrack *videoTrack = [comosition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    //视频采集通道
    AVAssetTrack * videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
    //把采集轨道数据加入到可变轨道中
    [videoTrack insertTimeRange:videoTimeRange ofTrack:videoAssetTrack atTime:nextClistartTime error:nil];
    
    //声音采集
    AVURLAsset *audioAsset = [[AVURLAsset alloc] initWithURL:audioInputUrl options:options];
    //因为视频较短 所以直接用了视频的长度 如果想要自动化需要自己写判断
    CMTimeRange audioTimeRange = videoTimeRange;
    //音频通道
    AVMutableCompositionTrack * audioTrack = [comosition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    //音频采集通道
    AVAssetTrack * audioAssetTrack = [[audioAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
    //加入合成轨道中
    [audioTrack insertTimeRange:audioTimeRange ofTrack:audioAssetTrack atTime:nextClistartTime error:nil];
    
//#warning test
    // 3.1 - Create AVMutableVideoCompositionInstruction
    AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration);
    
    // 3.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation.
    AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
    UIImageOrientation videoAssetOrientation_  = UIImageOrientationUp;
    BOOL isVideoAssetPortrait_  = NO;
    CGAffineTransform videoTransform = videoAssetTrack.preferredTransform;
    if (videoTransform.a == 0 && videoTransform.b == 1.0 && videoTransform.c == -1.0 && videoTransform.d == 0) {
        videoAssetOrientation_ = UIImageOrientationRight;
        isVideoAssetPortrait_ = YES;
    }
    if (videoTransform.a == 0 && videoTransform.b == -1.0 && videoTransform.c == 1.0 && videoTransform.d == 0) {
        videoAssetOrientation_ =  UIImageOrientationLeft;
        isVideoAssetPortrait_ = YES;
    }
    if (videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0) {
        videoAssetOrientation_ =  UIImageOrientationUp;
    }
    if (videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0) {
        videoAssetOrientation_ = UIImageOrientationDown;
    }
    [videolayerInstruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero];
    [videolayerInstruction setOpacity:0.0 atTime:videoAsset.duration];
    
    // 3.3 - Add instructions
    mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil];
    
    AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
    
    CGSize naturalSize;
    if(isVideoAssetPortrait_){
        naturalSize = CGSizeMake(videoAssetTrack.naturalSize.height, videoAssetTrack.naturalSize.width);
    } else {
        naturalSize = videoAssetTrack.naturalSize;
    }
    float renderWidth, renderHeight;
    renderWidth = naturalSize.width;
    renderHeight = naturalSize.height;
    mainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight);
    mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
    mainCompositionInst.frameDuration = CMTimeMake(1, 30);
//#warning test end 如果没有这段代码，合成后的视频会旋转90度
    //创建输出
    AVAssetExportSession * assetExport = [[AVAssetExportSession alloc] initWithAsset:comosition presetName:AVAssetExportPresetHighestQuality];  // 这里可以选择图片质量
    assetExport.outputURL = outPutUrl;      //输出路径
    assetExport.shouldOptimizeForNetworkUse = YES;  //是否优化  不太明白
    assetExport.outputFileType = AVFileTypeMPEG4; //输出类型
    assetExport.videoComposition = mainCompositionInst;
    [assetExport exportAsynchronouslyWithCompletionHandler:^{  // 合成完毕
        if (assetExport.status == AVAssetExportSessionStatusCompleted) {
            dispatch_async(dispatch_get_main_queue(), ^{    // 保存到相册
                if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum([outPutUrl path])) {
                    UISaveVideoAtPathToSavedPhotosAlbum([outPutUrl path], self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
                }
            });
        }else{ // 如果失败， 需要回调状态
            dispatch_async(dispatch_get_main_queue(), ^{    // 保存到相册
                [self showWarningWithText:@"压缩文件失败！"];
            });
        }
    }];
}

// 保存视频到相册
- (void)video:(NSString*)videoPath didFinishSavingWithError:(NSError*)error contextInfo:(void*)contextInfo {
    if (error) {
        [self showWarningWithText:@"保存相册失败！"];
    }else {
        //取出这个视频
        PHFetchOptions *options = [[PHFetchOptions alloc] init];
        options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; //按创建日期获取
        PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
        PHAsset *phasset = [assetsFetchResults lastObject];
        if (phasset) {
            if (phasset.mediaType == PHAssetMediaTypeVideo) {   // 是视频文件
                __weak typeof(self) weakSelf = self;
                PHImageManager *manager = [PHImageManager defaultManager];
                [manager requestAVAssetForVideo:phasset options:nil resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
                    AVURLAsset *urlAsset = (AVURLAsset *)asset;
                    // 返回成功的URL
                    dispatch_async(dispatch_get_main_queue(), ^{
                        //此处再次判断这个视频文件的时间防止误传,以5分钟为界限
                        if (![weakSelf videoTimeCheck:asset.creationDate.dateValue]) {
                            [weakSelf showWarningWithText:@"获取不到刚才的录屏文件，请重试!"];
                            return ;
                        }
                        // 代理成功回调
                        if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(saveVideoSuscessWithAssetURl:)]) {
                            [weakSelf.delegate saveVideoSuscessWithAssetURl:urlAsset];
                        }
                    });
                }];
            } else {
                [self showWarningWithText:@"未成功保存视频！"];
            }
        } else {
            [self showWarningWithText:@"未成功保存视频！"];
        }
    }
    // 删除沙盒缓存的视频文件
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if([fileManager fileExistsAtPath:videoPath]){
        [fileManager removeItemAtPath:videoPath error:nil];
        NSLog(@"删除沙盒临时存储视频成功！");
    }
}

// 结束录屏时, 失败提示！
- (void)showWarningWithText:(NSString *)text {
    if (self.delegate && [self.delegate respondsToSelector:@selector(didStopRecordWithErrorString:)]) {
        [self.delegate didStopRecordWithErrorString:text];
    }
}

// 开启录屏时，失败提醒！
- (void)showStartRecordErrorWithText:(NSString *)text {
    if (self.delegate && [self.delegate respondsToSelector:@selector(didStartRecordWithErrorString:)]) {
        [self.delegate didStartRecordWithErrorString:text];
    }
}

@end
