package cn.i2edu.speech_plugin

import android.app.Activity
import android.content.Context
import android.text.TextUtils
import android.widget.Toast
import cn.i2edu.dubbing_lib.bean.SimpleWord
import cn.i2edu.dubbing_lib.util.AudioEvaluatorUtil
import cn.i2edu.dubbing_lib.util.EvaluatorCallBack
import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.ReadSentenceResult
import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.XmlResultParser
import com.alibaba.fastjson.JSON
import com.googlecode.mp4parser.authoring.Movie
import com.googlecode.mp4parser.authoring.Track
import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder
import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator
import com.googlecode.mp4parser.authoring.tracks.AppendTrack
import com.iflytek.cloud.EvaluatorResult
import com.iflytek.cloud.SpeechConstant
import com.iflytek.cloud.SpeechError
import com.iflytek.cloud.SpeechUtility
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import java.io.File
import java.io.RandomAccessFile
import java.util.*

class SpeechPlugin: MethodCallHandler {

    companion object {
        private lateinit var context: Context
        private lateinit var channel: MethodChannel
        private var evaluatorType: Int = 0

        @JvmStatic
        fun registerWith(registrar: Registrar) {
            if (registrar.activity() == null) return
            channel = MethodChannel(registrar.messenger(), "speech_plugin")
            context = registrar.activeContext()
            channel.setMethodCallHandler(SpeechPlugin())
        }
    }

  override fun onMethodCall(call: MethodCall, result: Result) {
    if (call.method == "getPlatformVersion") {
      result.success("Android ${android.os.Build.VERSION.RELEASE}")
    } else if (call.method == "initSpeechSdk") {
      SpeechUtility.createUtility(context, SpeechConstant.APPID +"=5da1549c")
      result.success(true)
    } else if (call.method == "evaluatorByAudio") {
        val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
        val index = call.argument<Int>("index")!!
        val videoId = call.argument<String>("videoId")!!
        val recordPath = call.argument<String>("recordPath")!!
        val en = call.argument<String>("en")!!
        evaluatorType = call.argument<Int>("evaluatorType")!!

        evaluatorRecord(pathEvaluatorDecode, index, recordPath, en, false)
    } else if (call.method == "evaluatorByMp4") {
        val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
        val index = call.argument<Int>("index")!!
        val videoId = call.argument<String>("videoId")!!
        val recordPath = call.argument<String>("recordPath")!!
        val en = call.argument<String>("en")!!
        evaluatorType = call.argument<Int>("evaluatorType")!!

        evaluatorVideoRecord(pathEvaluatorDecode, index, videoId, recordPath, en)
    } else {
      result.notImplemented()
    }
  }

  private fun evaluatorVideoRecord(pathEvaluatorDecode: String, index: Int, videoId: String, recordPath: String, en: String) {
    try {
      val movie = MovieCreator.build (recordPath)
      val audioTracks = arrayListOf<Track>()
      for (t in movie.tracks){
        if (t.handler == "soun") {
          audioTracks.add(t)
        }
      }
      val result =  Movie()
      if (audioTracks.size > 0) {
        val array = arrayOfNulls<Track>(audioTracks.size)
        audioTracks.toArray(array)
        result.addTrack(AppendTrack(*array))
      }
      val out = DefaultMp4Builder().build(result)
      try {
        val fc = RandomAccessFile("$pathEvaluatorDecode/${videoId}_$index.aac", "rw").channel
        out.writeContainer(fc)
        fc.close()
        evaluatorRecord(pathEvaluatorDecode, index, "$pathEvaluatorDecode/${videoId}_$index.aac", en, true)
      } catch ( e: Exception) {
        e.printStackTrace()
      }
    }catch (e: Exception) {
      e.printStackTrace()
    }
  }

  private fun evaluatorRecord(pathEvaluatorDecode: String, index: Int, recordPath: String, en: String, isVideo: Boolean) {
    val dir = File(pathEvaluatorDecode)
    if (!dir.exists()) dir.mkdirs()
    val decodePath = pathEvaluatorDecode + UUID.randomUUID().toString() + ".pcm"
    AudioEvaluatorUtil.getInstance(context = context)
            .setEvaluatorCallBack(object : EvaluatorCallBack {
              override fun onResult(result: EvaluatorResult) {
                (context as Activity).runOnUiThread {
                  if (isVideo) {
                    try {
                      File(recordPath).delete()
                    } catch (e: java.lang.Exception) {
                      e.printStackTrace()
                    }
                  }
                  val builder = StringBuilder()
                  builder.append(result.resultString)
                  if (!TextUtils.isEmpty(builder)) {
                    val resultParser = XmlResultParser()
                    val parseResult = resultParser.parse(builder.toString()) as ReadSentenceResult
//                    Toast.makeText(context,
//                            "识别成功,结果：${if (parseResult.is_rejected) "您在乱读哦" else "您没乱读结果为:${parseResult.total_score}"}", Toast.LENGTH_SHORT).show()
                    val formatWords = arrayListOf<SimpleWord>()
                    for (sentence in parseResult.sentences) {
                      val words = sentence.words
                      for (word in words) {
                        // 过滤掉sil、 silv 表示静音， fil 表示噪音
                        if (word.content == "sil" || word.content == "silv" || word.content == "fil")
                          continue
                        formatWords.add(SimpleWord(word.content, word.total_score))
                      }
                    }

                    channel.invokeMethod("evaluatorResult",
                            mapOf("index" to index,"score" to (if(parseResult.is_rejected) null else parseResult.total_score), "integrity_score" to (if(parseResult.is_rejected) null else parseResult.integrity_score),
                                    "accuracy_score" to (if(parseResult.is_rejected) null else parseResult.accuracy_score), "fluency_score" to (if(parseResult.is_rejected) null else parseResult.fluency_score),
                                    "words" to JSON.toJSONString(formatWords)))
                  } else {
//                    Toast.makeText(context, "识别失败,结果为空", Toast.LENGTH_SHORT).show()
                    channel.invokeMethod("evaluatorResult", mapOf("index" to index,"score" to null, "integrity_score" to null, "accuracy_score" to null, "fluency_score" to null))
                  }
                }
              }

              override fun onError(error: SpeechError) {
                (context as Activity).runOnUiThread {
                  //                  Toast.makeText(activity.applicationContext, "识别失败,错误描述：${error.errorDescription},错误码:${error.errorCode}",
//                          Toast.LENGTH_SHORT).show()
                  channel.invokeMethod("evaluatorResult", mapOf("index" to index,"score" to null))
                }
              }
            })
            ?.startEvaluator(en, recordPath, decodePath, evaluatorType)
  }

}
