package com.tsmobile.app.voice

import android.media.MediaCodec
import android.media.MediaCodecInfo
import android.media.MediaFormat
import android.os.Build
import java.nio.ByteBuffer

/**
 * Opus 编码器 — 使用 MediaCodec 硬件/系统编码
 *
 * 要求 API 29+ (Android 10)，因为 MediaFormat.MIMETYPE_AUDIO_OPUS 在 API 29 引入。
 * 对于低版本设备，isAvailable() 返回 false，语音发送不可用。
 */
class OpusEncoder {

    private var codec: MediaCodec? = null
    private var isStarted = false

    companion object {
        const val SAMPLE_RATE = 48000
        const val CHANNELS = 1
        const val BIT_RATE = 32000 // 32kbps VOIP
        const val FRAME_DURATION_MS = 20
        const val FRAME_SIZE = SAMPLE_RATE * FRAME_DURATION_MS / 1000 // 960 samples

        /** 是否可用（需要 API 29+） */
        fun isAvailable(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
    }

    /**
     * 启动编码器
     * @return true 如果成功启动
     */
    fun start(): Boolean {
        if (!isAvailable()) return false
        if (isStarted) return true

        try {
            val format = MediaFormat.createAudioFormat(
                MediaFormat.MIMETYPE_AUDIO_OPUS,
                SAMPLE_RATE,
                CHANNELS,
            ).apply {
                setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE)
                setInteger(MediaFormat.KEY_COMPLEXITY, 5)
                // Opus 编码需要 PCM 16-bit 输入
                setInteger(
                    MediaFormat.KEY_PCM_ENCODING,
                    android.media.AudioFormat.ENCODING_PCM_16BIT,
                )
            }

            codec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_OPUS).apply {
                configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
                start()
            }
            isStarted = true
            return true
        } catch (e: Exception) {
            android.util.Log.e("OpusEncoder", "Failed to start encoder", e)
            release()
            return false
        }
    }

    /**
     * 编码一帧 PCM 数据为 Opus
     * @param pcm 16-bit PCM 采样数据（960 samples = 20ms @ 48kHz）
     * @return Opus 编码后的数据，失败返回 null
     */
    fun encode(pcm: ShortArray): ByteArray? {
        val c = codec ?: return null
        if (!isStarted) return null

        try {
            // 输入：将 ShortArray 转为 ByteArray (little-endian)
            val inputBuffer = pcmToBytes(pcm)
            val inputIndex = c.dequeueInputBuffer(10_000) // 10ms timeout
            if (inputIndex >= 0) {
                val buf = c.getInputBuffer(inputIndex) ?: return null
                buf.clear()
                buf.put(inputBuffer)
                c.queueInputBuffer(inputIndex, 0, inputBuffer.size, 0, 0)
            }

            // 输出
            val bufferInfo = MediaCodec.BufferInfo()
            val outputIndex = c.dequeueOutputBuffer(bufferInfo, 10_000)
            if (outputIndex >= 0) {
                val outputBuffer = c.getOutputBuffer(outputIndex) ?: return null
                val opusData = ByteArray(bufferInfo.size)
                outputBuffer.get(opusData)
                c.releaseOutputBuffer(outputIndex, false)
                return opusData
            }
        } catch (e: Exception) {
            android.util.Log.e("OpusEncoder", "Encode error", e)
        }
        return null
    }

    /** 停止并释放资源 */
    fun release() {
        try {
            codec?.stop()
            codec?.release()
        } catch (_: Exception) {}
        codec = null
        isStarted = false
    }

    /** ShortArray (PCM 16-bit) → ByteArray (little-endian) */
    private fun pcmToBytes(pcm: ShortArray): ByteArray {
        val bytes = ByteArray(pcm.size * 2)
        for (i in pcm.indices) {
            bytes[i * 2] = (pcm[i].toInt() and 0xFF).toByte()
            bytes[i * 2 + 1] = (pcm[i].toInt() shr 8 and 0xFF).toByte()
        }
        return bytes
    }
}
