//
//  SpatialVideoWriter.swift
//  tdvideo
//
//  Created by mac on 2024/2/22.
//。两个普通视频合成空间视频

import UIKit
import AVFoundation
import VideoToolbox
import Photos

class SpatialVideoWriter {
    
    private func removeExistingFile(at outputVideoURL: URL) throws {
        do {
            try FileManager.default.removeItem(atPath: outputVideoURL.path)
            print("视频文件删除成功")
        } catch {
            print("删除视频文件出错：\(error)")
        }
    }
    
    func writeSpatialVideo(leftEyeVideoURL: URL, rightEyeVideoURL: URL, outputVideoURL: URL, completion: @escaping (Bool, Error?) -> Void) {
        
        do {
            
            try removeExistingFile(at: outputVideoURL)
            
            let leftEyeAsset = AVURLAsset(url: leftEyeVideoURL)
            let rightEyeAsset = AVURLAsset(url: rightEyeVideoURL)

            

            let leftVideoTrack = leftEyeAsset.tracks(withMediaType: .video).first!
            let rightVideoTrack = rightEyeAsset.tracks(withMediaType: .video).first!
            let letAudioTrack = leftEyeAsset.tracks(withMediaType: .audio).first!
           
            // 创建视频输入
            let assetWriter = try AVAssetWriter(outputURL: outputVideoURL, fileType: .mov)
            let videoSettings: [String: Any] = [
                AVVideoWidthKey: leftVideoTrack.naturalSize.width,
                AVVideoHeightKey: leftVideoTrack.naturalSize.height,
                AVVideoCodecKey: AVVideoCodecType.hevc,
                AVVideoCompressionPropertiesKey: [
                    kVTCompressionPropertyKey_MVHEVCVideoLayerIDs: [0, 1] as CFArray,
                    kCMFormatDescriptionExtension_HorizontalFieldOfView: 90_000, // asset-specific, in thousandths of a degree
                    kVTCompressionPropertyKey_HorizontalDisparityAdjustment: 200, // asset-specific
                ]
            ]
            let input_video = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
            input_video.expectsMediaDataInRealTime = true
            let adaptor_inputVideo = AVAssetWriterInputTaggedPixelBufferGroupAdaptor(assetWriterInput: input_video)
            assetWriter.add(input_video)
            
            
            //附加视频标记元数据信息
            let metadataItem_1 = AVMutableMetadataItem()
            metadataItem_1.identifier = .quickTimeMetadataSpatialOverCaptureQualityScoringVersion
            metadataItem_1.dataType = kCMMetadataDataType_QuickTimeMetadataDirection as String
            metadataItem_1.value = String("ff") as (NSCopying & NSObjectProtocol)
            metadataItem_1.extraAttributes = [.info:"vpexport"]
            
//            let metadataItem_2 = AVMutableMetadataItem()
//            metadataItem_2.identifier = .quickTimeMetadataSpatialOverCaptureQualityScoringVersion
//            metadataItem_2.dataType = kCMMetadataDataType_QuickTimeMetadataDirection as String
//            metadataItem_2.value = String("ff") as (NSCopying & NSObjectProtocol)
//            metadataItem_2.extraAttributes = [.info:"vpexport"]
            
//            let atmg:AVMutableTimedMetadataGroup = AVMutableTimedMetadataGroup(items: [metadataItem_1,metadataItem_2], timeRange: CMTimeRange(start: .zero, duration: .positiveInfinity))
//            let desc:CMMetadataFormatDescription? = atmg.copyFormatDescription()
//            let asaArray =  AVOutputSettingsAssistant.availableOutputSettingsPresets()
//            asaArray.forEach { preset in
//                var asa = AVOutputSettingsAssistant(preset: preset)
//                print("asa:\n\(asa?.videoSettings)  \n\(asa?.audioSettings)\n")
//            }
//            
//            let input_metadata = AVAssetWriterInput.init(mediaType: .metadata, outputSettings: nil, sourceFormatHint: desc)
////            let input_metadata = AVAssetWriterInput.init(mediaType: .metadata, outputSettings: nil)
//            let metadataAdaptor = AVAssetWriterInputMetadataAdaptor(assetWriterInput: input_metadata)
//            if assetWriter.canAdd(input_metadata) {
//                assetWriter.add(input_metadata)
//            }
//            else {
//                print("assetwriter can't add input_metadata....")
//            }
            
            assetWriter.metadata = [metadataItem_1]

            
            
            
            

            
            // 创建音频输入
            let inputSettings_Audio = [
                AVFormatIDKey: kAudioFormatLinearPCM, // 指定未压缩格式
                AVSampleRateKey: 44100,
                AVNumberOfChannelsKey: 2,
                AVLinearPCMIsBigEndianKey:true,
                AVLinearPCMIsFloatKey:true,
                AVLinearPCMBitDepthKey:32,
                AVLinearPCMIsNonInterleaved:false,
            ] as [String:Any]
            

            let writerInput_Audio_left = AVAssetWriterInput.init(mediaType: .audio, outputSettings: inputSettings_Audio)
            
            writerInput_Audio_left.expectsMediaDataInRealTime = false
            if  assetWriter.canAdd(writerInput_Audio_left) {
                assetWriter.add(writerInput_Audio_left)
                print("assetWriter 添加writerInput_Audio_left成功...")
            }
            else {
                print("assetWriter 添加writerInput_Audio_left失败...")
            }
//            AVMetadataFormat
            assetWriter.startWriting()
            assetWriter.startSession(atSourceTime: .zero)

            
            
            //创建视频读取
            let leftEyeReader = try AVAssetReader(asset: leftEyeAsset)
            let rightEyeReader = try AVAssetReader(asset: rightEyeAsset)

            let readerOutputSettings: [String:Any] = [
                kCVPixelBufferPixelFormatTypeKey as String:  NSNumber(value: kCVPixelFormatType_32BGRA),
                kCVPixelBufferWidthKey as String: leftVideoTrack.naturalSize.width,
                kCVPixelBufferHeightKey as String: leftVideoTrack.naturalSize.height
            ]

            let leftEyeOutput = AVAssetReaderTrackOutput(track: leftVideoTrack, outputSettings: readerOutputSettings)
            let rightEyeOutput = AVAssetReaderTrackOutput(track:rightVideoTrack , outputSettings: readerOutputSettings)

            leftEyeReader.add(leftEyeOutput)
            rightEyeReader.add(rightEyeOutput)

            //加载音频轨道读取 从左眼视频读取
            let outputSettings_Audio = [
                AVFormatIDKey: kAudioFormatLinearPCM, // 指定未压缩格式
                AVSampleRateKey: 44100,
                AVNumberOfChannelsKey: 2,
            ]
//            
            
            
            let output_audio_left =  AVAssetReaderTrackOutput(
                track: letAudioTrack,
                outputSettings:outputSettings_Audio
            )
            
            if leftEyeReader.canAdd(output_audio_left){
                leftEyeReader.add(output_audio_left)
                print("output_audio_left添加音频read output成功。。。。")
            }
            else{
                print("output_audio_left添加音频read output失败。。。。")
            }
            
            
            leftEyeReader.startReading()
            rightEyeReader.startReading()
            
            
            
            
            

            while let leftBuffer = leftEyeOutput.copyNextSampleBuffer(),
                  let rightBuffer = rightEyeOutput.copyNextSampleBuffer() {

                let time = Date().timeIntervalSince1970
                print("获取了一帧" + String(time))
                // 获取左右眼视频帧的像素缓冲区
                guard let leftFrameBuffer = CMSampleBufferGetImageBuffer(leftBuffer),
                      let rightFrameBuffer = CMSampleBufferGetImageBuffer(rightBuffer) else {
                    print("获取左右眼像素缓冲区失败")
                    return
                }

                // 创建 CMTaggedBuffer 数组，包含左右眼视图的像素缓冲区
                let leftCVPixelBuffer = leftFrameBuffer as CVPixelBuffer
                let rightCVPixelBuffer = rightFrameBuffer as CVPixelBuffer

                let left = CMTaggedBuffer(tags: [.stereoView(.leftEye), .videoLayerID(0)], pixelBuffer: leftCVPixelBuffer)
                let right = CMTaggedBuffer(tags: [.stereoView(.rightEye), .videoLayerID(1)], pixelBuffer: rightCVPixelBuffer)

                while !adaptor_inputVideo.assetWriterInput.isReadyForMoreMediaData {
                    // 等待直到 writerInput 准备好接收下一个视频帧
                    Thread.sleep(forTimeInterval: 0.1) // 暂停一段时间，避免过度占用资源
                }
                let appendResult = adaptor_inputVideo.appendTaggedBuffers([left, right], withPresentationTime: leftBuffer.presentationTimeStamp)
                print("appendResult :\(appendResult)")
            }

            
            self.addAudio(assetTrackOutput: output_audio_left, audio_input: writerInput_Audio_left)
            
            //附加元素据
//            let appendATMGResult = metadataAdaptor.append(atmg)
//            
//            print("atmg result:\(appendATMGResult)")
            
            // 完成写入
            print("完成写入")
            writerInput_Audio_left.markAsFinished()
            input_video.markAsFinished()
            outputVideoURL.stopAccessingSecurityScopedResource()
            assetWriter.finishWriting { [self] in
                print("可以保存")
                completion(true, nil)
                
//                self.saveVideoToLibrary(videoURL: outputVideoURL, completion: completion)
            }
        } catch {
            print("生成失败")
            completion(false, error)
        }
    }

    
    //追加音频
    func  addAudio(assetTrackOutput:AVAssetReaderTrackOutput,audio_input:AVAssetWriterInput) {
            while let sample = assetTrackOutput.copyNextSampleBuffer() {
                print("audio read buffer....")
                let formatDesc:CMFormatDescription = CMSampleBufferGetFormatDescription(sample)!
                let mediaType:CMMediaType  = CMFormatDescriptionGetMediaType(formatDesc);
                if mediaType == kCMMediaType_Audio {
                    if audio_input.isReadyForMoreMediaData {
                        if audio_input.append(sample) == false {
//                            print("追加音频失败....:\(String(describing: self.writer.error?.localizedDescription))")
                            print("追加音频失败.....")
                        }
                        else{
                            print("audio 追加成功....")
                        }
                    }
                    else {
                        print("audio 追加还未准备好...")

                    }
                }
                else {
                    print("不是audio类型...")
                }
            }
        print("audio func 执行完毕。。。。...")
    }
}
