package com.lila.wakeup.kws

import android.annotation.SuppressLint
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import android.util.Log
import com.lila.wakeup.Config

/**
 * 麦克风音频采集封装。
 *
 * 设计要点：
 *  - AudioSource 用 VOICE_RECOGNITION（自动启用 NS/AGC，省去自己降噪）
 *  - 16kHz / mono / 16-bit PCM（与 sherpa-onnx 模型严格对齐）
 *  - 10ms 帧（160 sample）便于和 VAD 对齐
 *  - 暂停时完全 release AudioRecord，释放麦克风给 RTC SDK
 *
 * 注：这是常驻读取线程，不是 ForegroundService 主线程。
 */
class AudioCapture(
    /** 每读到一帧 PCM 数据时回调，参数为 16-bit PCM short[] */
    private val onFrame: (ShortArray) -> Unit
) {
    companion object {
        private const val TAG = "KwsService.Audio"
    }

    @Volatile private var record: AudioRecord? = null
    @Volatile private var thread: Thread? = null
    @Volatile private var running = false

    @SuppressLint("MissingPermission")  // 权限由 MainActivity 运行时申请
    fun start() {
        if (running) {
            Log.w(TAG, "start() called while already running, skip")
            return
        }

        val minBuf = AudioRecord.getMinBufferSize(
            Config.SAMPLE_RATE, Config.CHANNEL_CONFIG, Config.ENCODING
        )
        // 至少 100ms ring buffer，多于 minBuf 防止音频丢帧
        val bufSize = maxOf(minBuf, Config.SAMPLE_RATE * 2 * 100 / 1000)

        record = AudioRecord.Builder()
            .setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION)
            .setAudioFormat(
                AudioFormat.Builder()
                    .setSampleRate(Config.SAMPLE_RATE)
                    .setChannelMask(Config.CHANNEL_CONFIG)
                    .setEncoding(Config.ENCODING)
                    .build()
            )
            .setBufferSizeInBytes(bufSize)
            .build()

        if (record?.state != AudioRecord.STATE_INITIALIZED) {
            Log.e(TAG, "AudioRecord init failed, state=${record?.state}")
            release()
            return
        }

        record?.startRecording()
        running = true
        Log.i(TAG, "AudioRecord started, bufSize=$bufSize bytes")

        thread = Thread {
            val frame = ShortArray(Config.FRAME_SAMPLES)
            while (running) {
                val n = record?.read(frame, 0, frame.size) ?: 0
                if (n > 0) {
                    onFrame(frame)
                } else if (n < 0) {
                    Log.e(TAG, "AudioRecord.read error code=$n, abort")
                    break
                }
            }
            Log.i(TAG, "AudioCapture thread exit")
        }.apply {
            name = "KwsAudioCapture"
            priority = Thread.NORM_PRIORITY + 2   // 略高于普通线程
            isDaemon = true
            start()
        }
    }

    fun stop() {
        if (!running) return
        running = false
        thread?.join(500)
        thread = null
        release()
        Log.i(TAG, "AudioRecord stopped")
    }

    private fun release() {
        record?.let {
            try {
                if (it.recordingState == AudioRecord.RECORDSTATE_RECORDING) {
                    it.stop()
                }
                it.release()
            } catch (e: Exception) {
                Log.e(TAG, "release failed: ${e.message}")
            }
        }
        record = null
    }

    fun isRunning(): Boolean = running
}
