package com.example.exportmedia.video

import android.graphics.Bitmap
import com.example.exportmedia.MediaCallBack
import com.example.exportmedia.MediaHelper
import com.example.exportmedia.data.AudioSource
import io.reactivex.Observable
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter

class MovieMaker(
        private val mediaHelper: MediaHelper,
        private val imageDir: String,
        private val fps: Int,
        private val audioSources: ArrayList<AudioSource>,
        private val inputFilePath:String
) {

    private constructor(builder: Builder) : this(
            builder.mediaHelper,
            builder.imageDir,
            builder.fps,
            builder.audioSources,
            builder.inputFilePath
    )

    fun output(file: File): Observable<String> {
        val arrayList = ArrayList<String>()

        for (audioSource in audioSources) {
            arrayList.add("-itsoffset")
            arrayList.add("${audioSource.offsetSec}")
            arrayList.add("-i")
            arrayList.add("${audioSource.path}")
        }

        if (audioSources.size != 0) {
            arrayList.add("-filter_complex")
            arrayList.add("amix=inputs=${audioSources.size}:duration=longest")
        }

        arrayList.add("-f")
        arrayList.add("concat")

        arrayList.add("-safe")
        arrayList.add("0")

        arrayList.add("-i")
        arrayList.add(inputFilePath)

        arrayList.add("-pix_fmt")
        arrayList.add("yuv420p")

        arrayList.add("-c:v")
        arrayList.add("libx264")

        arrayList.add("-c:a")
        arrayList.add("aac")

        arrayList.add("-async")
        arrayList.add("1")

        arrayList.add("-y")
        arrayList.add(file.path)

        return Observable.create {
            mediaHelper.execute(arrayList.toTypedArray(), object : MediaCallBack {
                override fun onExecuteSuccess(message: String?) {
                    message?.let { it1 -> it.onNext(it1) }
                }

                override fun onExecuteFailed(message: String?) {
                    it.onError(Throwable(message))
                }

                override fun onExecuteFinish() {
                    it.onComplete()
                    clear()
                }
            })
        }
    }

    private fun clear() {
        val folder = File(imageDir)
        if (folder.isDirectory) {
            for (file in folder.listFiles()) {
                file.delete()
            }
        }
    }

    class Builder(internal val mediaHelper: MediaHelper) {

        var fps = 1

        var audioSources = ArrayList<AudioSource>()

        lateinit var inputFilePath: String

        internal val imageDir = mediaHelper.context?.filesDir?.path!! + File.separator + "EncodeImage"

        fun addImage(index: Int, bitmap: Bitmap): Observable<String> {
            return Observable.create<String> {
                val dirFile = File(imageDir)
                if (!dirFile.exists()) {
                    dirFile.mkdir()
                }

                val byteArrayOutputStream = ByteArrayOutputStream()
                val file = File(imageDir, "image$index.png")
                val fileOutputStream = FileOutputStream(file, false)

                try {
                    bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream)
                    val byteArray = byteArrayOutputStream.toByteArray()
                    fileOutputStream.write(byteArray)
                } catch (e: Exception) {
                    it.onError(e)
                } finally {
                    fileOutputStream.flush()
                    fileOutputStream.close()
                }

                it.onNext(file.path)
                it.onComplete()
            }
        }

        fun addInputFile(inputSceneStatus: LinkedHashMap<Int, Int>): Observable<String> {
            return Observable.create {
                val inputFile = File( imageDir , "input.txt")
                val writer = FileWriter(inputFile)
                try {
                    inputSceneStatus.forEach {
                        val file = File(imageDir, "image${it.key}.png")
                        writer.appendln("file \'${file.path}\'")
                        writer.appendln("duration ${(1f / fps) * it.value}")
                    }
                } catch (e: Exception) {

                } finally {
                    writer.flush()
                    writer.close()
                }
                it.onNext(inputFile.path)
                it.onComplete()
            }
        }

        fun build() = MovieMaker(this)
    }
}