//
//  ZZHCustomVideoCompositor.swift
//  SwiftProject
//
//  Created by aaa on 2024/4/18.
//

import Foundation
import Dispatch
import AVFoundation
import CoreImage
import CoreVideo

enum ZZHCustomVideoCompositoringError: Error {
    case invalidRequest
}


final class ZZHCustomVideoCompositor: NSObject, AVVideoCompositing {
    //自定义需要用的属性
    private let videoTranserConvertor = PlayByTransferConvertor()
    // 使用数组跟踪正在处理的请求
    var activeRequests: [AVAsynchronousVideoCompositionRequest] = []
    
    //类初始化时的重要配置
    private let queue = DispatchQueue(label: "ca.gurulogic.layer-video-compositor.render", qos: .default)
    private var renderContext: AVVideoCompositionRenderContext = AVVideoCompositionRenderContext()
    private var cancelled: Bool = false
    private static let pixelFormat = kCVPixelFormatType_32ARGB
    private let colorSpace = CGColorSpaceCreateDeviceRGB()
    private let ciContext: CIContext = {
        if let eaglContext = EAGLContext(api: .openGLES3) ?? EAGLContext(api: .openGLES2) {
            return CIContext(eaglContext: eaglContext)
        }
        return CIContext()
    }()
    
    let sourcePixelBufferAttributes: [String : Any]? = [
        kCVPixelBufferPixelFormatTypeKey as String : NSNumber(value: ZZHCustomVideoCompositor.pixelFormat),
        kCVPixelBufferOpenGLESCompatibilityKey as String : NSNumber(value: true),
    ]

    let requiredPixelBufferAttributesForRenderContext: [String : Any] = [
        kCVPixelBufferPixelFormatTypeKey as String : NSNumber(value: ZZHCustomVideoCompositor.pixelFormat),
        kCVPixelBufferOpenGLESCompatibilityKey as String : NSNumber(value: true),
    ]
    
    
    func renderContextChanged(_ newRenderContext: AVVideoCompositionRenderContext) {
        renderContext = newRenderContext
    }
    
    func startRequest(_ request: AVAsynchronousVideoCompositionRequest) {
        queue.async{
            // 将请求添加到正在处理的请求列表中
            self.activeRequests.append(request)
            
//            print("startRequest ....AVAsynchronousVideoCompositionRequest: \(self.cancelled)  request:\(request)")
            guard !self.cancelled else {
                print("startRequest cancell....")
                request.finishCancelledRequest()
                self.activeRequests.removeAll { $0 === request }
//                self.cancelled = false
                return
            }

//            print("startRequest queue:\(self.queue) current:\(Thread.current)")
//            CustomPlayerShareSemaphore.wait()
//            CustomPlayerShareRecursiveLock.lock()
            guard let renderedBuffer =  self.renderFrame(forRequest: request) else {
                request.finish(with: ZZHCustomVideoCompositoringError.invalidRequest)
                print("报了个异常,但是应该执行不到....")
                return
            }
//            CustomPlayerShareSemaphore.signal()
//            CustomPlayerShareRecursiveLock.unlock()
                request.finish(withComposedVideoFrame: renderedBuffer)
            // 从请求列表中移除已完成的请求
            self.activeRequests.removeAll { $0 === request }
//            print("完成执行 finish.....")
            
        }
    }

    func cancelAllPendingVideoCompositionRequests() {
        print("取消所有的pending 视频")
        cancelled = true
        queue.async(flags: .barrier) {
            print("取消所有的pending 视频  barrier")
            self.cancelled = false
        }
        
    }
    
    private func renderFrame(forRequest request: AVAsynchronousVideoCompositionRequest)-> CVPixelBuffer? {
        
        
        return  autoreleasepool {
            guard let instruction = request.videoCompositionInstruction as? ZZHCustomVideoCompositionInstruction else {
                return nil
            }
            guard let videoFrameBuffer = request.sourceFrame(byTrackID: instruction.videoTrackID) else {
                return nil
            }
            let compositionTime = request.compositionTime
            var ciImg:CIImage? = nil
            switch instruction.selectedIndex {
                case .monocular2D://双眼2d
//                ciImg = request.sourceImage
                break
                
            default :
                
                ciImg = self.otherModeImgWithMode(mode: instruction.selectedIndex,compositionTime: compositionTime,videoOriginalAsset: instruction.videoOriginalAsset,ao: instruction.assetOutput!)
                break
            }
            
            
            if let ciImg {
                guard let renderedBuffer = renderContext.newPixelBuffer() else {
                    return nil
                }
                ciContext.render(ciImg, to: renderedBuffer, bounds: ciImg.extent, colorSpace: self.colorSpace)
                
                return renderedBuffer
            }
            else {
                print("未合成成功.....")
                return videoFrameBuffer
            }
        }
    }
    

    func otherModeImgWithMode(mode:SpatialType,compositionTime:CMTime,videoOriginalAsset:AVAsset,ao:AVAssetReaderTrackOutput)->CIImage? {
        var ciImg:CIImage? = nil
        var presentTime:CMTime? = nil
        switch mode {
        case .crossedEyes://交叉眼
            ciImg = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type:mode, time: compositionTime)
            break
        
        
        case .fsbs://3d全宽
            ciImg = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
            break
        
        
        case .hsbs://3d半宽
            ciImg = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
            break
        
        
        case .parallelEyes://平行眼
            ciImg = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
            break
        
        case .redBlueSolid://红蓝立体
            ciImg = self.videoTranserConvertor.convertVideo(asset: videoOriginalAsset, assetOutput: ao, type: mode, time: compositionTime)
            break
        default:
            break
        }
        return ciImg
            
    }
    
    
    
    
}
