//
//  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 assetWriter = try AVAssetWriter(outputURL: outputVideoURL, fileType: .mov)

            let leftVideoTrack = leftEyeAsset.tracks(withMediaType: .video).first!
            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 = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
            assetWriter.add(input)

            let adaptor = AVAssetWriterInputTaggedPixelBufferGroupAdaptor(assetWriterInput: input)
            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: rightEyeAsset.tracks(withMediaType: .video).first!, outputSettings: readerOutputSettings)

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

            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.assetWriterInput.isReadyForMoreMediaData {
                    // 等待直到 writerInput 准备好接收下一个视频帧
                    Thread.sleep(forTimeInterval: 0.1) // 暂停一段时间，避免过度占用资源
                }
                adaptor.appendTaggedBuffers([left, right], withPresentationTime: leftBuffer.presentationTimeStamp)
            }

            // 完成写入
            print("完成写入")
            input.markAsFinished()
            outputVideoURL.stopAccessingSecurityScopedResource()
            assetWriter.finishWriting { [self] in
                print("可以保存")
                completion(true, nil)
                
                self.saveVideoToLibrary(videoURL: outputVideoURL, completion: completion)
            }
        } catch {
            print("生成失败")
            completion(false, error)
        }
    }

    private func saveVideoToLibrary(videoURL: URL, completion: @escaping (Bool, Error?) -> Void) {
        PHPhotoLibrary.shared().performChanges({
            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
        }) { success, error in
            if success {
                print("保存成功")
            } else if let error = error {
                print("保存失败")
            }
        }
    }
}
