package com.lila.wakeup.kws

import android.os.Handler
import android.os.Looper
import android.util.Log
import com.lila.wakeup.Config
import com.lila.wakeup.protocol.BroadcastSender
import java.util.concurrent.atomic.AtomicReference

/**
 * KWS 状态机 —— 协议 v2.1 规则的中央控制器。
 *
 * 三个状态：
 *  - [State.Idle]: 服务启动中（极短）
 *  - [State.Listening]: 正在监听唤醒词，命中即发 WAKEUP 广播
 *  - [State.Paused]: APP 主动暂停（含 silence_ms 二次保险窗口）
 *
 * silence_ms 实现：
 *  - 收到 PAUSE → 立即进入 Paused，记录 silenceUntilMs
 *  - silenceUntilMs 期间收到 RESUME → 等到 silenceUntilMs 过后才真正 resume（防 AI 自我唤醒）
 *  - 命中事件在 Paused 期间忽略
 *
 * 兜底超时：APP 漏发 RESUME 时，2 分钟自动 resume（详见 Config.PAUSE_TIMEOUT_MS）。
 */
class KwsStateMachine(
    private val engine: KwsEngine,
    private val sender: BroadcastSender,
    private val onTimeoutResume: () -> Unit = {}
) {
    companion object {
        private const val TAG = "KwsService.State"
    }

    sealed class State {
        object Idle : State()
        object Listening : State()
        data class Paused(val silenceUntilMs: Long, val reason: String) : State()
    }

    /** 用 Atomic 做无锁状态切换，避免读写竞态 */
    private val state = AtomicReference<State>(State.Idle)

    private val mainHandler = Handler(Looper.getMainLooper())
    private var timeoutRunnable: Runnable? = null
    private var deferredResumeRunnable: Runnable? = null

    /** 平滑窗口：连续 N 帧都命中才真正发 WAKEUP（v2.1 后验平滑） */
    private var consecutiveHits = 0

    fun transitionToListening() {
        state.set(State.Listening)
        consecutiveHits = 0
        Log.i(TAG, "[State] -> LISTENING")
    }

    /**
     * 收到 KWS_PAUSE 广播时调用。
     *
     * @param silenceMs 静默期（毫秒），默认 [Config.DEFAULT_SILENCE_MS]
     * @param reason 调用原因（仅日志）
     */
    fun onPauseReceived(silenceMs: Long, reason: String) {
        val until = System.currentTimeMillis() + silenceMs
        state.set(State.Paused(until, reason))
        consecutiveHits = 0
        Log.i(TAG, "[State] -> PAUSED reason=$reason silence_ms=$silenceMs until=$until")

        // 取消上一次的 deferred resume（如果有）
        cancelDeferredResume()

        // 启动 2 分钟兜底超时
        scheduleTimeoutResume()
    }

    /**
     * 收到 KWS_RESUME 广播时调用。
     */
    fun onResumeReceived(reason: String) {
        val current = state.get()
        when (current) {
            is State.Paused -> {
                val now = System.currentTimeMillis()
                if (now < current.silenceUntilMs) {
                    // silence 期间，延迟到 silence 满才真正 resume
                    val delay = current.silenceUntilMs - now
                    Log.i(TAG, "[State] RESUME deferred ${delay}ms (still in silence)")
                    deferredResumeRunnable = Runnable {
                        if (state.get() is State.Paused) {
                            transitionToListening()
                            Log.i(TAG, "[State] RESUME (silence elapsed) reason=$reason")
                        }
                    }.also { mainHandler.postDelayed(it, delay) }
                } else {
                    transitionToListening()
                    Log.i(TAG, "[State] RESUME immediate reason=$reason")
                }
            }
            is State.Listening -> {
                // 幂等：本就在监听态，无副作用
                Log.d(TAG, "[State] RESUME ignored, already LISTENING")
            }
            is State.Idle -> {
                transitionToListening()
                Log.i(TAG, "[State] Idle -> LISTENING via RESUME reason=$reason")
            }
        }
        cancelTimeoutResume()
    }

    /**
     * AudioCapture 每帧调用一次。在 Listening 态喂引擎并检查命中。
     */
    fun onAudioFrame(pcm: ShortArray) {
        if (state.get() !is State.Listening) return

        val result = engine.process(pcm)
        if (result.isHit) {
            consecutiveHits++
            if (consecutiveHits >= Config.SMOOTH_FRAMES) {
                // 命中且过平滑 → 发 WAKEUP 广播
                Log.i(TAG, "[KWS] HIT confirmed keyword=${result.keyword} smooth=$consecutiveHits")
                sender.sendWakeup(result.keyword, result.confidence)
                consecutiveHits = 0
            } else {
                Log.d(TAG, "[KWS] hit pending smooth=$consecutiveHits/${Config.SMOOTH_FRAMES}")
            }
        } else {
            // 未命中重置计数
            if (consecutiveHits > 0) consecutiveHits = 0
        }
    }

    fun shutdown() {
        cancelTimeoutResume()
        cancelDeferredResume()
        state.set(State.Idle)
    }

    // ============================================================
    // 内部：兜底定时器
    // ============================================================

    private fun scheduleTimeoutResume() {
        cancelTimeoutResume()
        timeoutRunnable = Runnable {
            Log.w(TAG, "[Tmout] PAUSE 超时（${Config.PAUSE_TIMEOUT_MS / 1000}s），强制 RESUME")
            transitionToListening()
            onTimeoutResume()
        }.also {
            mainHandler.postDelayed(it, Config.PAUSE_TIMEOUT_MS)
        }
    }

    private fun cancelTimeoutResume() {
        timeoutRunnable?.let { mainHandler.removeCallbacks(it) }
        timeoutRunnable = null
    }

    private fun cancelDeferredResume() {
        deferredResumeRunnable?.let { mainHandler.removeCallbacks(it) }
        deferredResumeRunnable = null
    }
}
