//
//  NXAVAssetExportSession.swift
//  PQSpeed
//
//  Created by ak on 2021/3/4.
//  Copyright © 2021 BytesFlow. All rights reserved.
//  功能：根据原视频导出新格式视频 如 修改fps

import UIKit
import BFCommonKit

class NXAVAssetExportSession: NSObject {
    // 使用 Core Animation 框架。设置视频水印、视频标题、动画浮层等。
    let animationTool: AVVideoCompositionCoreAnimationTool? = nil

    /// 导出视频
    /// - Parameters:
    ///   - inFilePath: 原视频文件路径
    ///   - outFilePath: 输出视频文件路径
    ///   - frameDuration: 输出 fps  e.g. CMTime(value: 1, timescale: 60)
    ///   - isAdjustRotationAngle: 是否旋转  默认为 true
    ///   - completeHander: 回调
    func exportAsynchronouslyWithCompletionHandler(inFilePath: String, outFilePath: String, frameDuration: CMTime, isAdjustRotationAngle: Bool = true, completeHander: @escaping (_ outFilePath: String?) -> Void) {
        BFLog(message: "原视频文件地址 \(inFilePath)")

        let avAsset = AVURLAsset(url: URL(fileURLWithPath: inFilePath), options: avAssertOptions)

        guard let assetVideoTrack = avAsset.tracks(withMediaType: .video).first else { return }
        guard let assetAudioTrack = avAsset.tracks(withMediaType: .audio).first else { return }
        let mixComposition = AVMutableComposition()
        guard let videoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) else { return }
        guard let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) else { return }
        do {
            try videoTrack.insertTimeRange(CMTimeRange(start: .zero, duration: avAsset.duration), of: assetVideoTrack, at: .zero)
            try audioTrack.insertTimeRange(CMTimeRange(start: .zero, duration: avAsset.duration), of: assetAudioTrack, at: .zero)
        } catch {
            NXLog(message: "error is \(error)")
        }

        videoTrack.preferredTransform = assetVideoTrack.preferredTransform

        let videoComposition = AVMutableVideoComposition()
        videoComposition.renderSize = videoTrack.naturalSize
        videoComposition.animationTool = animationTool
        videoComposition.frameDuration = frameDuration
        let instruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRange(start: .zero, duration: avAsset.duration)
        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
        instruction.layerInstructions = [layerInstruction]
        videoComposition.instructions = [instruction]

        if isAdjustRotationAngle {
            let rotationAngle = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: avAsset)

            var centerTranslate: CGAffineTransform = CGAffineTransform(translationX: 0, y: 0)
            var mixedTransform: CGAffineTransform = centerTranslate.rotated(by: 0)
            if rotationAngle == 90 {
                centerTranslate = CGAffineTransform(translationX: assetVideoTrack.naturalSize.height, y: 0)
                mixedTransform = centerTranslate.rotated(by: .pi / 2)
                videoComposition.renderSize = CGSize(width: assetVideoTrack.naturalSize.height, height: assetVideoTrack.naturalSize.width)
            } else if rotationAngle == 180 {
                centerTranslate = CGAffineTransform(translationX: assetVideoTrack.naturalSize.width, y: assetVideoTrack.naturalSize.height)
                mixedTransform = centerTranslate.rotated(by: .pi)
                videoComposition.renderSize = CGSize(width: assetVideoTrack.naturalSize.width, height: assetVideoTrack.naturalSize.height)
            } else if rotationAngle == 270 {
                centerTranslate = CGAffineTransform(translationX: 0, y: assetVideoTrack.naturalSize.width)
                mixedTransform = centerTranslate.rotated(by: .pi / 2 * 3)
                videoComposition.renderSize = CGSize(width: assetVideoTrack.naturalSize.height, height: assetVideoTrack.naturalSize.width)
            }

            layerInstruction.setTransform(mixedTransform, at: CMTime.zero)
        }

        let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
        exporter?.outputURL = URL(fileURLWithPath: outFilePath)
        exporter?.outputFileType = .mp4
        exporter?.shouldOptimizeForNetworkUse = true
        exporter?.videoComposition = videoComposition

        exporter?.exportAsynchronously { [weak self] in
//            guard let strongSelf = self else { return }

            if exporter!.status == .completed {
                BFLog(message: "导出完成 \(outFilePath)")
                completeHander(outFilePath)
            } else {
                print("导出出错 \(String(describing: exporter?.error))")
                completeHander("")
            }
        }
    }
}
