import android.content.ContentValues.TAG
import android.media.MediaCodec
import android.media.MediaCodecInfo
import android.media.MediaCodecList
import android.media.MediaFormat
import android.util.Log

/**
 * Encodes PCM audio data to AAC format
 * @param pcmData The raw PCM audio data to encode
 * @param sampleRate Sample rate of the audio (e.g., 44100)
 * @param channelCount Number of audio channels (1 for mono, 2 for stereo)
 * @return ByteArray containing the encoded AAC audio data
 */


fun listMediaCodecEncoders() {
    val codecList = MediaCodecList(MediaCodecList.ALL_CODECS) // List all codecs
    val codecs = codecList.codecInfos

    println("Available MediaCodec Encoders:")
    for (codec in codecs) {
        if (codec.isEncoder) {
            Log.e(TAG, "Encoder: ${codec.name}")
            // List supported types for this encoder
            val supportedTypes = codec.supportedTypes
            Log.w(TAG, "  Supported Types:")
            for (type in supportedTypes) {
                Log.w(TAG, "    $type")
            }
        }
    }
}

fun encodePcmToAac(pcmData: ByteArray): ByteArray {
    // Create a format for the encoder
    var sampleRate = 48000
    var channelCount = 1
//    listMediaCodecEncoders();
    val format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_OPUS, sampleRate, channelCount)
    format.setInteger(MediaFormat.KEY_BIT_RATE, 64000)  // 128kbps
//    format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC)
//    format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, pcmData.size)

    // Create and configure the encoder
    val codec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_OPUS)
    codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
    codec.start()

    // Use ByteArrayOutputStream to collect encoded data
    val encodedBytes = mutableListOf<Byte>()
    val bufferInfo = MediaCodec.BufferInfo()

    var allInputSubmitted = false
    var inputOffset = 0
    var presentationTimeUs = 0L
    val frameSize = 1024 * channelCount * 2  // Typical frame size for AAC encoding (1024 samples, 16-bit PCM)

    try {
        while (!allInputSubmitted || bufferInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
            // Submit input data to encoder
            if (!allInputSubmitted) {
                val inputBufferId = codec.dequeueInputBuffer(10000)
                if (inputBufferId >= 0) {
                    val inputBuffer = codec.getInputBuffer(inputBufferId)
                    inputBuffer?.clear()

                    // Calculate how many bytes to read
                    val bytesToRead = if (inputOffset < pcmData.size) {
                        minOf(inputBuffer!!.capacity(), pcmData.size - inputOffset)
                    } else {
                        0
                    }

                    if (bytesToRead > 0) {
                        // Copy data from byte array to input buffer
                        inputBuffer!!.put(pcmData, inputOffset, bytesToRead)
                        inputOffset += bytesToRead

                        // Calculate presentation time in microseconds
                        // (samples / sample rate) * 1_000_000
                        val samples = bytesToRead / (2 * channelCount)  // 16-bit samples
                        presentationTimeUs += samples * 1_000_000L / sampleRate

                        codec.queueInputBuffer(
                            inputBufferId,
                            0,
                            bytesToRead,
                            presentationTimeUs,
                            0
                        )
                    } else {
                        // End of input data
                        codec.queueInputBuffer(
                            inputBufferId,
                            0,
                            0,
                            presentationTimeUs,
                            MediaCodec.BUFFER_FLAG_END_OF_STREAM
                        )
                        allInputSubmitted = true
                    }
                }
            }

            // Get encoded data from encoder
            val outputBufferId = codec.dequeueOutputBuffer(bufferInfo, 10000)
            when {
                outputBufferId >= 0 -> {
                    val outputBuffer = codec.getOutputBuffer(outputBufferId)

                    if (outputBuffer != null && bufferInfo.size > 0) {
                        // Copy encoded data to our result buffer
                        val encodedChunk = ByteArray(bufferInfo.size)
                        outputBuffer.position(bufferInfo.offset)
                        outputBuffer.limit(bufferInfo.offset + bufferInfo.size)
                        outputBuffer.get(encodedChunk)
                        encodedBytes.addAll(encodedChunk.toList())
                    }

                    codec.releaseOutputBuffer(outputBufferId, false)

                    if ((bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                        break
                    }
                }
                outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> {
                    // You might want to store the format for muxing
                    val newFormat = codec.outputFormat
                    // Log.d("MediaCodec", "Output format changed: $newFormat")
                }
            }
        }
    } finally {
        codec.stop()
        codec.release()
    }
    return encodedBytes.toByteArray()
    }

