//
import AVFoundation
import Foundation
//  NXAudioRecorder.swift
//  PQSpeed
//
//  Created by ak on 2021/1/23.
//  Copyright © 2021 BytesFlow. All rights reserved.
//  本类功能：录制声音，并转换成 MP3
//  alse see https://www.jianshu.com/p/971fff236881
import UIKit

// 录制时长
public typealias  RecorderProgross = (_ time: Float64) -> Void

public class NXAudioRecorder {
    public let recorder: AVAudioRecorder

    public var finishClosure: ((_ isSuccess: Bool, _ url: String) -> Void)? {
        return delegateHandler.finishClosure
    }

    /// 由于AVAudioRecorderDelegate继承NSObjectProtocol 所以引入这个类处理代理避免污染主类
    public  var delegateHandler = EditAudioRecorderDelegateHandler()

    public  var recorderProgross: RecorderProgross?
    public  var session: AVAudioSession!
    public  var recordFilePath: String!

    public  var displayLink: CADisplayLink?

    /// 初始化录音器
    /// - Parameter path: 保存的文件全路径，注意文件后缀一定要是 caf
    /// - Throws: description
    public init(path: String) throws {
        // 1,判断目录文件夹是否存在
        recordFilePath = path
        BFLog(message: "recorder file path is \(String(describing: recordFilePath))")

        // 2,参数
        let fileURL = URL(fileURLWithPath: recordFilePath)
        // 注意设置参数 设置不对就无法录制
        let settings: [String: Any] = [
            AVFormatIDKey: kAudioFormatLinearPCM,
            AVSampleRateKey: 16000.0,
            AVNumberOfChannelsKey: 1,
            AVEncoderBitDepthHintKey: 16,
//            AVLinearPCMIsFloatKey:true, // 不要打开ios 13有杂音
            AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue, // 录音质量
        ]
        recorder = try AVAudioRecorder(url: fileURL, settings: settings)
        recorder.isMeteringEnabled = true
        recorder.delegate = delegateHandler
        recorder.prepareToRecord()
    }

    /// 开始录制
    public func startRecord() {
        if recorder.isRecording {
            BFLog(message: "正在录制中。。")
            return
        }

        startTimer()

        if AVAudioSession.sharedInstance().category != .playAndRecord {
            do {
                try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .defaultToSpeaker)
                try AVAudioSession.sharedInstance().setActive(true)
            } catch {
                BFLog(message: error)
            }
        }

        session = AVAudioSession.sharedInstance()
        session.requestRecordPermission { granted in
            if granted {
                DispatchQueue.global().async {
                    DispatchQueue.main.async {}
                }
            } else {}
        }

        recorder.record()
    }

    // 暂停录制
    public func pauseRecord() {
        recorder.pause()
    }

    // 停止录制
    public func stopRecord(_ closure: @escaping (_ isSuccess: Bool, _ url: String) -> Void) {
        if !recorder.isRecording {
            BFLog(message: "不是录制状态")
        }

        stopTimer()

        delegateHandler.finishClosure = closure

        recorder.stop()
    }

    @objc func displayLinkClick(_: CADisplayLink) {
        recorder.updateMeters()

        BFLog(message: "当前录制时间长 \(String(describing: recorder.currentTime)) 波值：\(String(describing: recorder.averagePower(forChannel: 0)))")
        if recorderProgross != nil {
            recorderProgross!(recorder.currentTime)
        }
    }

    // 开始计时
    public func startTimer() {
        if displayLink == nil {
            // 创建对象
            displayLink = CADisplayLink(target: self, selector: #selector(displayLinkClick(_:)))
            // 设置触发频率 这个周期可以通过frameInterval属性设置，CADisplayLink的selector每秒调用次数=60/frameInterval。比如当frameInterval设为2，每秒调用就变成30次
//            if #available(iOS 10.0, *) {
//                displayLink?.preferredFramesPerSecond = 1
//            } else {
            displayLink?.frameInterval = 1
//            }
            // 加入循环
            displayLink?.add(to: RunLoop.main, forMode: RunLoop.Mode.default)
        }
    }

    // 停止计时
    public  func stopTimer() {
        if displayLink != nil {
            displayLink?.isPaused = true
            // 将定时器移除主循环
            displayLink?.remove(from: RunLoop.main, forMode: RunLoop.Mode.default)
            // 停止定时器
            displayLink?.invalidate()
            displayLink = nil
        }
    }
}

public class EditAudioRecorderDelegateHandler: NSObject {
    public var finishClosure: ((_ flag: Bool, _ url: String) -> Void)?
}

extension EditAudioRecorderDelegateHandler: AVAudioRecorderDelegate {
    public  func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        BFLog(message: "完成录音结果 is \(flag) url is \(recorder.url)")
        if flag {
            finishClosure?(true, recorder.url.relativePath)
        }
    }

    public  func audioRecorderEncodeErrorDidOccur(_: AVAudioRecorder, error: Error?) {
        guard let error = error else { return }
        BFLog(message: error)
    }
}
