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

import UIKit
import AVFoundation
import VideoToolbox
import Photos

class SpatialVideoDataWriter {
    
    var assetWriter:AVAssetWriter!
    var videoSettings: [String: Any]!
    var input_video:AVAssetWriterInput!
    let inputSettings_Audio = [
        AVFormatIDKey: kAudioFormatLinearPCM, // 指定未压缩格式
        AVSampleRateKey: 44100,
        AVNumberOfChannelsKey: 2,
        AVLinearPCMIsBigEndianKey:true,
        AVLinearPCMIsFloatKey:true,
        AVLinearPCMBitDepthKey:32,
        AVLinearPCMIsNonInterleaved:false,
    ] as [String:Any]
    
    var writerInput_Audio_left:AVAssetWriterInput!
    var adaptor_inputVideo:AVAssetWriterInputTaggedPixelBufferGroupAdaptor!
    
    var isReady:Bool {
        get {
            return assetWriter != nil
        }
    }
    
    var haveStartedSession:Bool = false
    
    var outputVideoURL:URL!
    
    var leftSampleBuffer:SVDWStack<CMSampleBuffer> = SVDWStack()
    var rightSampleBuffer:SVDWStack<CMSampleBuffer>  = SVDWStack()
    var audioSmapleBuffer:SVDWStack<CMSampleBuffer>  = SVDWStack()
    
    
    //MARK: - Function实现
    func exAddLeftSampleBuffer(_ buffer:CMSampleBuffer) {
        initWriterWithSmapleBuffer(buffer)
        leftSampleBuffer.push(buffer)
        autoWriteData()
    }
    
    func exAddRightSampleBuffer(_ buffer:CMSampleBuffer) {
        initWriterWithSmapleBuffer(buffer)
        rightSampleBuffer.push(buffer)
        autoWriteData()
    }
    
    func exAddAudioSampleBuffer(_ buffer:CMSampleBuffer) {
        audioSmapleBuffer.push(buffer)
        autoWriteData()
    }
    
    //开始自动写入
    func autoWriteData(){
        if !leftSampleBuffer.isEmpty() && !rightSampleBuffer.isEmpty() && !audioSmapleBuffer.isEmpty() {
            writeVideoData(leftSamplebuffer: leftSampleBuffer.pop()!, rightSamplebuffer: rightSampleBuffer.pop()!, audioSamplebuffer: audioSmapleBuffer.pop()!)
        }
    }
    
    func initWriterWithSmapleBuffer(_ buffer:CMSampleBuffer){
        if !self.isReady {
            let pixelBuffer = CMSampleBufferGetImageBuffer(buffer)
            if let pixelBuffer {
                let videoWidth = CVPixelBufferGetWidth(pixelBuffer)
                let videoHeight = CVPixelBufferGetHeight(pixelBuffer)
                writeVideoDataInit(videoWidth: Double(videoWidth), videoHeight: Double(videoHeight))
            }
        }
    }
    
    
    
    //第一步,写入之前应当先初始化配置信息
    func writeVideoDataInit(videoWidth:Double,videoHeight:Double) {
        do {
            // 创建视频输入
            assetWriter = try AVAssetWriter(outputURL: outputVideoURL, fileType: .mov)
            
            videoSettings = [
                AVVideoWidthKey: videoWidth,
                AVVideoHeightKey: videoHeight,
                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
                ]
            ]
//            var ac = videoSettings[AVVideoCompressionPropertiesKey] as! [String:Any]
//            ac[kVTCompressionPropertyKey_MVHEVCVideoLayerIDs as String] = [0, 1]
//            ac[kCMFormatDescriptionExtension_HorizontalFieldOfView as String] = 90_000
//            ac[kVTCompressionPropertyKey_HorizontalDisparityAdjustment as String] = 200
//            videoSettings[AVVideoCompressionPropertiesKey] = ac
            
            
            input_video = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
            input_video.expectsMediaDataInRealTime = true
            adaptor_inputVideo = AVAssetWriterInputTaggedPixelBufferGroupAdaptor(assetWriterInput: input_video)
            assetWriter.add(input_video)
            
            // 创建音频输入
            writerInput_Audio_left = AVAssetWriterInput.init(mediaType: .audio, outputSettings: inputSettings_Audio)
            writerInput_Audio_left.expectsMediaDataInRealTime = true
            if  assetWriter.canAdd(writerInput_Audio_left) {
                assetWriter.add(writerInput_Audio_left)
                print("assetWriter 添加writerInput_Audio_left成功...")
            }
            else {
                print("assetWriter 添加writerInput_Audio_left失败...")
            }
            assetWriter.startWriting()
            assetWriter.startSession(atSourceTime: .zero)
            
        }
        catch {
            print("writeVideoDataInit 初始化遇到问题:\(error)")
        }
    }
    
    //第三部,写入完毕之后应当释放配置信息
    func writeVideoDataDeInit(completion: @escaping (Bool, Error?) -> Void) {
        writerInput_Audio_left.markAsFinished()
        input_video.markAsFinished()
        assetWriter.finishWriting {
            print("assetWriter.finishWriting  可以保存")
            completion(true, nil)
        }
        haveStartedSession = false
        assetWriter = nil
        input_video = nil
        adaptor_inputVideo = nil
        writerInput_Audio_left = nil
        
    }
    
    //第二步,开始写入数据
    func writeVideoData(leftSamplebuffer:CMSampleBuffer,rightSamplebuffer:CMSampleBuffer,audioSamplebuffer:CMSampleBuffer) {
        
        //追加视频帧
        guard let leftCVPixelBuffer = CMSampleBufferGetImageBuffer(leftSamplebuffer) ,
              let rightCVPixelBuffer = CMSampleBufferGetImageBuffer(rightSamplebuffer)  else {
            print("获取左右眼像素缓冲区失败")
            return
        }

        
        if ( !haveStartedSession ) {
            assetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(leftSamplebuffer))
            haveStartedSession = true
        }
        
        // 创建 CMTaggedBuffer 数组，包含左右眼视图的像素缓冲区

        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: leftSamplebuffer.presentationTimeStamp)
        print("appendVideoImage samplebuffer Frame Result :\(appendResult)")
        
        
        //追加音频帧
        if writerInput_Audio_left.isReadyForMoreMediaData {
            if writerInput_Audio_left.append(audioSamplebuffer) == false {
                print("追加音频失败.....")
            }
            else{
                print("audio 追加成功....")
            }
        }
        else {
            print("audio 追加还未准备好...")

        }
        
    }
}
