package com.tsystems.flutter_vosk_wakeword

import android.Manifest
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import android.os.Process
import android.util.Log
import androidx.annotation.RequiresPermission
import org.vosk.Recognizer
import org.vosk.android.RecognitionListener
import java.util.concurrent.Executors

class AudioRecorder(private val recognizer: Recognizer,
                    private val listener: RecognitionListener) {
    companion object {
        private const val TAG = "AudioRecorder"
        private const val SAMPLE_RATE = 16000
        private const val BUFFER_SIZE_FACTOR = 2
    }

    private var audioRecord: AudioRecord? = null
    private val executor = Executors.newSingleThreadExecutor()

    fun isRecording(): Boolean = audioRecord?.recordingState == AudioRecord.RECORDSTATE_RECORDING

    @RequiresPermission(Manifest.permission.RECORD_AUDIO)
    fun start() {
        if (isRecording()) return

        val bufferSize = AudioRecord.getMinBufferSize(
            SAMPLE_RATE,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT
        ) * BUFFER_SIZE_FACTOR

        // 权限检查应该在调用此方法之前在App层完成
        audioRecord = AudioRecord(
            MediaRecorder.AudioSource.VOICE_RECOGNITION,
            SAMPLE_RATE,
            AudioFormat.CHANNEL_IN_MONO,
            AudioFormat.ENCODING_PCM_16BIT,
            bufferSize
        )

        if (audioRecord?.state == AudioRecord.STATE_INITIALIZED) {
            audioRecord?.startRecording()
            executor.execute {
                Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO)
                val buffer = ByteArray(bufferSize)
                while (isRecording()) {
                    val nread = audioRecord?.read(buffer, 0, buffer.size) ?: 0
                    if (nread > 0) {
                        // 判断是否有完整的识别结果
                        val ac = recognizer.acceptWaveForm(buffer, nread)
                        val partialResultText = recognizer.partialResult
                        val resultText = recognizer.result
                        val pRes1 = VoskRecognizer.parsePartialResult(partialResultText)
                        val pRes2 = VoskRecognizer.parseFinalResult(partialResultText)
                        val finalResult = VoskRecognizer.parseFinalResult(resultText)
                        val partialResult = pRes1.ifEmpty { pRes2.ifEmpty { "" } }
//                        Log.i(TAG, "Partial: $partialResultText, Parsed: $partialResult; Final: $resultText, Parsed: $finalResult; Accepted: $ac")
                        if (partialResult.isNotBlank() || finalResult.isNotBlank()) {
                            Log.i(
                                TAG,
                                "Partial result: ${partialResult}, Final result: $finalResult"
                            )
                            // 去除 [unk] 的影响
                            if (partialResult == "[unk]" || finalResult == "[unk]") {
                                continue
                            }
                            if (ac) {
                                listener.onResult(resultText)
                                recognizer.reset()
                            } else {
                                listener.onPartialResult(partialResultText)
//                                recognizer.reset()
                            }
                        }
                    }
                }
                listener.onFinalResult(recognizer.finalResult)
            }
            Log.i(TAG, "Audio recording started.")
        } else {
            Log.e(TAG, "AudioRecord initialization failed.")
            listener.onError(Exception("AudioRecord initialization failed."))
        }
    }

    fun stop() {
        if (isRecording()) {
            audioRecord?.stop()
            audioRecord?.release()
            audioRecord = null
            Log.i(TAG, "Audio recording stopped.")
        }
    }
}