package app.dudu.audio

import android.annotation.SuppressLint
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import android.util.Log
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.concurrent.thread

/**
 * 麦克风采集：16kHz / 16bit / mono PCM，按协议每 100ms 一帧 = 3200 字节
 * （对齐 server/pkg/protocol/ws.go: SampleRate/FrameMillis/FrameBytes）。
 *
 * 调用方必须先确认 RECORD_AUDIO 已授权（IME 内无法弹权限框，未授权时引导主 App）。
 */
class AudioStreamer(
    private val onFrame: (ByteArray) -> Unit,
    private val onError: (Throwable) -> Unit,
) {
    private val running = AtomicBoolean(false)
    private var worker: Thread? = null

    @SuppressLint("MissingPermission") // 权限由调用方（KeyboardController）预检
    fun start() {
        if (!running.compareAndSet(false, true)) return
        worker = thread(name = "dudu-audio") {
            var record: AudioRecord? = null
            try {
                val minBuf = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL, ENCODING)
                record = AudioRecord(
                    MediaRecorder.AudioSource.VOICE_RECOGNITION,
                    SAMPLE_RATE, CHANNEL, ENCODING,
                    maxOf(minBuf, FRAME_BYTES * 4),
                )
                check(record.state == AudioRecord.STATE_INITIALIZED) { "AudioRecord 初始化失败" }
                record.startRecording()
                check(record.recordingState == AudioRecord.RECORDSTATE_RECORDING) { "麦克风被占用或不可用" }

                while (running.get()) {
                    val frame = ByteArray(FRAME_BYTES)
                    var off = 0
                    while (off < FRAME_BYTES && running.get()) {
                        val n = record.read(frame, off, FRAME_BYTES - off)
                        if (n < 0) throw IllegalStateException("AudioRecord.read 错误码 $n")
                        off += n
                    }
                    if (off == FRAME_BYTES) onFrame(frame)
                }
            } catch (t: Throwable) {
                if (running.get()) {
                    Log.w(TAG, "音频采集异常", t)
                    onError(t)
                }
            } finally {
                runCatching {
                    record?.stop()
                    record?.release()
                }
            }
        }
    }

    fun stop() {
        running.set(false)
        worker = null
    }

    companion object {
        private const val TAG = "DuduAudio"
        const val SAMPLE_RATE = 16000
        const val FRAME_BYTES = 3200 // 100ms * 16000Hz * 16bit mono
        private const val CHANNEL = AudioFormat.CHANNEL_IN_MONO
        private const val ENCODING = AudioFormat.ENCODING_PCM_16BIT
    }
}
