package cn.i2edu.dubbing_lib.util

import android.content.Context
import android.os.Message
import android.text.TextUtils
import cn.i2edu.dubbing_lib.audioUtils.AudioDecoder
import cn.i2edu.dubbing_lib.audioUtils.AudioEncoder
import cn.i2edu.dubbing_lib.audioUtils.compose.AudioComposer
import cn.i2edu.dubbing_lib.callback.MixinHandlerCallback
import java.io.File
import java.util.*
import kotlin.collections.ArrayList

interface MixinPaintedCallBack {
    fun onResult(resultPath: String)
    fun onError(message: String)
}

class MixinPaintedUtil private constructor(private val context: Context) : MixinHandlerCallback {
    private val mixinHandler: MixinHandler<MixinPaintedUtil> = MixinHandler(this)
    // 合成需要的参数
    private lateinit var audioPaths: List<String> // 未解码录音路径
    private lateinit var bgmPath: String // 未解码背景音频路径
    private lateinit var durationList: List<Long>
    private lateinit var endTimeList: List<Long>
    // result save
    private lateinit var decodeAudioPaths: ArrayList<String> // 解码录音路径
    private lateinit var decodeBgmPath: String // 解码背景音频路径
    private lateinit var decodeAsyncBgmPath: String // 合成音频后的未解码路径
    // dir
    private lateinit var decodeDirPath: String // 解码文件夹地址
    private lateinit var mixinFilePath: String
    private lateinit var encodePath: String // 指定合成音频后的文件.mp3路径

    private var mixinPaintedCallBack: MixinPaintedCallBack? = null
    private val pausableThreadPool: PausableThreadPool = PausableThreadPool(1)
    private val TAG: String = "MixinPaintedUtil"

    companion object {
        @Volatile
        private var instance: MixinPaintedUtil? = null

        fun getInstance(context: Context) = instance
                ?: synchronized(this) {
                    instance
                            ?: MixinPaintedUtil(context)
                                    .also { instance = it }
                }
    }

    fun initParams(
            audioPaths: List<String>, bgmPath: String, durationList: List<Long>, endTimeList: List<Long>, decodeDirPath: String,
            mixinFilePath: String, resultPath: String
    ): MixinPaintedUtil {
        this.audioPaths = audioPaths
        this.bgmPath = bgmPath
        this.durationList = durationList
        this.endTimeList = endTimeList
        this.decodeDirPath = decodeDirPath
        this.mixinFilePath = mixinFilePath
        this.encodePath = resultPath
        return instance!!
    }

    fun setComposeCallBack(callback: MixinPaintedCallBack): MixinPaintedUtil {
        this.mixinPaintedCallBack = callback
        return instance!!
    }

    fun startMixin() {
        val message = Message.obtain()
        message.what = HandlerMessage.START_MIX_IN.value
        mixinHandler.sendMessage(message)
    }

    private fun decodeAudio() {
        if (TextUtils.isEmpty(decodeDirPath)) return
        decodeAudioPaths = arrayListOf()
        pausableThreadPool.execute {
            // 解码录音音频
            for (path in audioPaths) {
                val decodedPath = doDecode(UUID.randomUUID().toString(), path, decodeDirPath)
                if (decodedPath == null) {
                    mixinPaintedCallBack?.onError("decodeBgmAudio failed")
                    return@execute
                }
                decodeAudioPaths.add(decodedPath)
            }
            // 解码背景音乐
            val decodedPath = doDecode(UUID.randomUUID().toString(), bgmPath, decodeDirPath)
            if (decodedPath == null) {
                mixinPaintedCallBack?.onError("decodeBgmAudio failed")
                return@execute
            }
            decodeBgmPath = decodedPath
            // step3  背景音乐与录音合成
            val message = Message.obtain()
            message.what = HandlerMessage.AUDIO_DECODE_FINISHED.value
            mixinHandler.sendMessage(message)
        }
    }

    private fun syncAudios() {
        // 合成背景音乐和录音 （从尾部开始）
        val tempPath = arrayOf<String>(decodeBgmPath)
        pausableThreadPool.execute {
            AudioComposer.composeAudio(tempPath[0],
                    decodeAudioPaths,
                    mixinFilePath,
                    false,
                    endTimeList,
                    durationList,
                    object : AudioComposer.ComposeAudioInterface {
                        override fun composeSuccess(resultPath: String?) {
                            decodeAsyncBgmPath = resultPath!!
                            val message = Message.obtain()
                            message.what = HandlerMessage.AUDIO_SYN_FINISHED.value
                            mixinHandler.sendMessage(message)
                        }

                        override fun composeFail() {
                            mixinPaintedCallBack?.onError("async bgm and record failed")
                        }
                    })
        }
    }

    private fun encodeAsynAudio() {
        pausableThreadPool.execute {
            val accEncoder = AudioEncoder
                    .createAccEncoder(decodeAsyncBgmPath)
            val isEncodeFinished = !TextUtils.isEmpty(accEncoder.encodeToFile(encodePath))
            if (!isEncodeFinished) {
                mixinPaintedCallBack?.onError("encode async audio failed")
                return@execute
            }
            val msg = Message()
            msg.what = HandlerMessage.AUDIO_MIX_VIDIO_FINISHED.value
            mixinHandler.sendMessage(msg)
        }
    }

    private fun audioMixPaintedFinish() {
        mixinPaintedCallBack?.onResult(encodePath)
    }

    private fun doDecode(fileName: String, path: String, saveDirPath: String): String? {
        try {
            // 解码后的路径
            val decodeFile = File(saveDirPath)
            if (!decodeFile.exists()) {
                decodeFile.mkdirs()
            }
            val finalFile = File(decodeFile.absolutePath + "/" + fileName)
            if (!finalFile.exists()) {
                finalFile.createNewFile()
            }
            val audioDec = AudioDecoder
                    .createDefualtDecoder(path)
            audioDec.decodeToFile(finalFile.absolutePath)
            return finalFile.absolutePath
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    override fun onHandleMessage(msg: Message) {
        when (msg.what) {
            HandlerMessage.START_MIX_IN.value -> {
                // step2 解码背景音乐及配音音频
                decodeAudio()
            }
            HandlerMessage.AUDIO_DECODE_FINISHED.value -> {
                // step3  背景音乐与录音合成
                syncAudios()
            }
            HandlerMessage.AUDIO_SYN_FINISHED.value -> {
                // step4 编码音频
                encodeAsynAudio()
            }
            HandlerMessage.AUDIO_MIX_VIDIO_FINISHED.value -> {
                audioMixPaintedFinish()
            }
        }
    }
}