package com.tsystems.flutter_vosk_wakeword

import android.Manifest
import android.app.Service
import android.content.Intent
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import android.os.Process
import android.util.Log
import androidx.annotation.RequiresPermission


import org.vosk.Model
import org.vosk.Recognizer
import org.vosk.android.RecognitionListener
import org.vosk.android.StorageService
import java.io.IOException

class WakewordService: Service(), RecognitionListener {

    companion object {
        const val ACTION_INITIALIZE = "ACTION_INITIALIZE"
        const val ACTION_START = "ACTION_START"
        const val ACTION_STOP = "ACTION_STOP"
        const val EXTRA_WAKE_WORDS = "EXTRA_WAKE_WORDS"
        private const val TAG = "WakewordService"
        private const val ASSET_MODEL_DIR = "model-cn"
        private const val LOCAL_MODEL_DIR = "model"

        // 冷却时间: 同一唤醒词触发后在此毫秒内不再重复广播
        private const val DETECTION_COOLDOWN_MS = 2500L
    }

    private val mainHandle = Handler(Looper.getMainLooper())

    private var model: Model? = null
    private var recognizer: Recognizer? = null
    private var audioRecorder: AudioRecorder? = null
    private var wakeWordDetector: WakewordDetector? = null

    private var pendingStart = false
    private var modelLoading = false

    // 去重/状态控制
    private var lastWakeWord: String? = null
    private var lastDetectTs: Long = 0L
    private var suppressUntilFinal = false

    override fun onCreate() {
        super.onCreate()
        Log.w(TAG, "onCreate pid=${Process.myPid()} thread=${Thread.currentThread().name}")
        dumpAssets()
    }

    private fun dumpAssets() {
        try {
            val root = assets.list("")?.joinToString()
            Log.w(TAG, "assets root=$root")
            val cn = assets.list("model-cn")?.joinToString()
            Log.w(TAG, "assets/model-cn=$cn")
        } catch (e: Exception) {
            Log.e(TAG, "dumpAssets error", e)
        }
    }

    @RequiresPermission(Manifest.permission.RECORD_AUDIO)
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val action = intent?.action
        when (action) {
            ACTION_INITIALIZE -> {
                val wakeWords = intent.getStringArrayListExtra(EXTRA_WAKE_WORDS)
                Log.i(TAG, "ACTION_INITIALIZE wakeWords=${wakeWords.toString()}")
                if (wakeWords != null && wakeWords.isNotEmpty()) {
                    initialize(wakeWords)
                } else {
                    Log.e(TAG, "No valid wake words found in Intent extras.")
                }
            }
            ACTION_START -> {
                pendingStart = true
                Log.i(TAG, "ACTION_START received (modelReady=${model != null}, loading=$modelLoading)")
                startRecognition()
            }
            ACTION_STOP -> {
                Log.i(TAG, "ACTION_STOP received")
                stopRecognition()
            }
        }

        return START_STICKY
    }

    private fun initialize(wakeWords: ArrayList<String>) {
        if (model != null) {
            Log.i(TAG, "Model already loaded; skip initialize.")
            return
        }
        if (modelLoading) {
            Log.i(TAG, "Model already loading; skip duplicate initialize.")
            return
        }
        Log.i(TAG, "initialize() begin")

        try {
            stopRecognition()
            wakeWordDetector = WakewordDetector(wakeWords)
            modelLoading = true
            Log.i(TAG, "Submitting StorageService.unpack source=model-cn target=model")
            StorageService.unpack(this,
                ASSET_MODEL_DIR,
                LOCAL_MODEL_DIR,
                { loadedModel ->
                    Log.i(TAG, "Vosk model loaded successfully")
                    this.model = loadedModel
                    modelLoading = false
                    if (pendingStart) {
                        mainHandle.post {
                            startRecognition()
                        }
                    }
                },
                { exception ->
                    modelLoading = false
                    val errorMsg = "Failed to unpack the model: ${exception.message}"
                    Log.e(TAG, errorMsg, exception)
                    EventReceiver.broadcastError(this, errorMsg)
                })
        } catch (e: IOException) {
            modelLoading = false
            Log.e(TAG, "Failed to load Vosk model", e)
            EventReceiver.broadcastError(this, "Failed to load Vosk model: ${e.message}")
        }
    }

    @RequiresPermission(Manifest.permission.RECORD_AUDIO)
    private fun startRecognition() {
        val modelReady = model != null
        Log.i(TAG, "startRecognition(modelReady=$modelReady pendingStart=$pendingStart loading=$modelLoading)")
        if (!pendingStart) {
            Log.i(TAG, "No pending start request; abort.")
            return
        }
        if (!modelReady) {
            Log.i(TAG, "Model not ready yet; start deferred.")
            return
        }
        if (audioRecorder?.isRecording() == true) {
            Log.w(TAG, "Already recording.")
            return
        }
        try {
            val grammar = wakeWordDetector?.getVoskGrammar()
            val currentRecognizer = Recognizer(model, 16000.0f, grammar)
            recognizer = currentRecognizer

            audioRecorder = AudioRecorder(currentRecognizer, this)
            audioRecorder?.start()
            Log.i(TAG, "Recognition started.")
            resetDetectionState()
        } catch (e: Exception) {
            val errorMsg = "Failed to start recognition: ${e.message}"
            Log.e(TAG, "Failed to start recognition", e)
            EventReceiver.broadcastError(this, errorMsg)
        }
    }

    private fun stopRecognition() {
        Log.i(TAG, "stopRecognition()")
        audioRecorder?.stop()
        audioRecorder = null
        recognizer?.close()
        recognizer = null
        Log.i(TAG, "Recognition stopped.")
        resetDetectionState()
    }

    private fun resetDetectionState() {
        suppressUntilFinal = false
        lastWakeWord = null
        lastDetectTs = 0L
    }

    // --- RecognitionListener Callbacks ---
    override fun onPartialResult(hypothesis: String?) {
        hypothesis ?: return
        val partialText = VoskRecognizer.parsePartialResult(hypothesis)
        if (partialText.isBlank()) return
        Log.d(TAG, "partial=$partialText suppress=$suppressUntilFinal")

        if (suppressUntilFinal) return

        if (wakeWordDetector?.checkForWakeWord(partialText) == true) {
            val now = System.currentTimeMillis()
            if (shouldBroadcast(partialText, now)) {
                broadcastWake(partialText, now, source = "partial")
                // 抑制后续重复直到 finalResult 或超时
                suppressUntilFinal = true
            }
        }
    }

    override fun onResult(hypothesis: String?) {
        hypothesis ?: return
        val finalText = VoskRecognizer.parseFinalResult(hypothesis)
        if (finalText.isBlank()) return
        Log.d(TAG, "result=$finalText suppress=$suppressUntilFinal")

        if (wakeWordDetector?.checkForWakeWord(finalText) == true) {
            val now = System.currentTimeMillis()
            if (shouldBroadcast(finalText, now)) {
                broadcastWake(finalText, now, source = "final")
            }
        }
        // final / result 结束一轮，允许下一次
        suppressUntilFinal = false
    }

    override fun onFinalResult(hypothesis: String?) {
        // 已在 onResult 处理; 这里可以忽略或调用 onResult
        onResult(hypothesis)
    }

    private fun shouldBroadcast(word: String, now: Long): Boolean {
        val cooldownPassed = (now - lastDetectTs) > DETECTION_COOLDOWN_MS
        val differentWord = word != lastWakeWord
        return cooldownPassed || differentWord
    }

    private fun broadcastWake(word: String, now: Long, source: String) {
        lastWakeWord = word
        lastDetectTs = now
        recognizer?.reset()
        Log.i(TAG, "Wake word detected($source): $word")
        EventReceiver.broadcastWakeWord(this, word)
        // 重置识别器状态，为下一次唤醒做准备
    }

    override fun onError(e: Exception?) {
        Log.e(TAG, "Recognition error", e)
        EventReceiver.broadcastError(this, e?.message ?: "Unknown recognition error")
        suppressUntilFinal = false
    }

    override fun onTimeout() {
        Log.w(TAG, "Recognition timeout.")
        // 超时视为一轮结束
        suppressUntilFinal = false
    }

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onDestroy() {
        stopRecognition()
        model?.close()
        model = null
        super.onDestroy()
        Log.i(TAG, "WakewordService destroyed.")
    }
}
