package top.yeij.cyrene.voice.stt

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.speech.RecognitionListener
import android.speech.RecognizerIntent
import android.speech.SpeechRecognizer
import android.util.Log
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow

class SpeechRecognizer(private val context: Context) : SttProvider {

    private var recognizer: android.speech.SpeechRecognizer? = null

    private val _isListening = MutableStateFlow(false)
    override val isListening: StateFlow<Boolean> = _isListening.asStateFlow()

    private val _partialResult = MutableStateFlow("")
    override val partialResult: StateFlow<String> = _partialResult.asStateFlow()

    private val _finalResult = MutableSharedFlow<SttResult>(extraBufferCapacity = 8)
    override val finalResult: SharedFlow<SttResult> = _finalResult.asSharedFlow()

    private val _onError = MutableSharedFlow<String>(extraBufferCapacity = 8)
    override val onError: SharedFlow<String> = _onError.asSharedFlow()

    override fun start() {
        if (!android.speech.SpeechRecognizer.isRecognitionAvailable(context)) {
            Log.w(TAG, "Speech recognition not available on this device")
            _onError.tryEmit("语音识别不可用")
            return
        }

        cancel()
        recognizer = android.speech.SpeechRecognizer.createSpeechRecognizer(context).apply {
            setRecognitionListener(object : RecognitionListener {
                override fun onReadyForSpeech(params: Bundle?) {
                    _isListening.value = true
                    _partialResult.value = ""
                }

                override fun onBeginningOfSpeech() {}

                override fun onRmsChanged(rmsdB: Float) {}

                override fun onBufferReceived(buffer: ByteArray?) {}

                override fun onEndOfSpeech() {}

                override fun onError(error: Int) {
                    _isListening.value = false
                    val msg = when (error) {
                        android.speech.SpeechRecognizer.ERROR_NETWORK -> "网络连接失败"
                        android.speech.SpeechRecognizer.ERROR_NETWORK_TIMEOUT -> "网络超时"
                        android.speech.SpeechRecognizer.ERROR_AUDIO -> "音频录制错误"
                        android.speech.SpeechRecognizer.ERROR_SERVER -> "服务器错误"
                        android.speech.SpeechRecognizer.ERROR_CLIENT -> "客户端错误"
                        android.speech.SpeechRecognizer.ERROR_SPEECH_TIMEOUT -> "未检测到语音"
                        android.speech.SpeechRecognizer.ERROR_NO_MATCH -> "未能识别"
                        android.speech.SpeechRecognizer.ERROR_RECOGNIZER_BUSY -> "语音引擎忙碌"
                        android.speech.SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> "缺少录音权限"
                        else -> "未知错误 ($error)"
                    }
                    Log.w(TAG, "Recognition error: $msg")
                    _onError.tryEmit(msg)
                }

                override fun onResults(results: Bundle?) {
                    _isListening.value = false
                    val matches = results?.getStringArrayList(android.speech.SpeechRecognizer.RESULTS_RECOGNITION)
                    if (!matches.isNullOrEmpty()) {
                        _finalResult.tryEmit(SttResult(text = matches[0], isFinal = true))
                    }
                }

                override fun onPartialResults(partialResults: Bundle?) {
                    val matches = partialResults?.getStringArrayList(android.speech.SpeechRecognizer.RESULTS_RECOGNITION)
                    if (!matches.isNullOrEmpty()) {
                        _partialResult.value = matches[0]
                    }
                }

                override fun onEvent(eventType: Int, params: Bundle?) {}
            })

            val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
                putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
                putExtra(RecognizerIntent.EXTRA_LANGUAGE, "zh-CN")
                putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
                putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1)
            }
            startListening(intent)
        }
    }

    override fun stop() {
        recognizer?.stopListening()
        _isListening.value = false
    }

    override fun cancel() {
        recognizer?.cancel()
        recognizer?.destroy()
        recognizer = null
        _isListening.value = false
        _partialResult.value = ""
    }

    companion object {
        private const val TAG = "CyreneSTT"
    }
}
