package audio

import com.sun.jna.Memory
import com.sun.jna.Pointer
import org.slf4j.Logger
import org.slf4j.LoggerFactory

/**
 * OpusStreamReceiver is a class that handles receiving Opus audio streams.
 * @param deviceID The ID of the audio device to use for playback.
 * @param samplingrate The sampling rate for the audio stream, default is 16000 Hz.
 * @throws Exception if the device cannot be set.
 */
@Suppress("unused")
class OpusStreamReceiver(val deviceID: Int, val samplingrate: Int = 16000) {
    private val bass = Bass.Instance
    private val bassopus = BASSOPUS.Instance
    private var filehandle = 0
    private val logger : Logger = LoggerFactory.getLogger(OpusStreamReceiver::class.java)
    var isPlaying = false




    /**
     * Starts the Opus stream playback.
     * @return true if the stream started successfully, false otherwise.
     */
    fun Start() : Boolean{

        if (AudioUtility.InitDevice(deviceID, samplingrate)){
            val opushead = BASSOPUS.BASS_OPUS_HEAD()
            opushead.version = 1
            opushead.channels = 1
            opushead.inputrate = samplingrate
            val procpush = Pointer(-1)
            filehandle = bassopus.BASS_OPUS_StreamCreate(opushead,0, procpush, null)
            if (filehandle != 0){
                if (bass.BASS_ChannelPlay(filehandle,false)){
                    isPlaying = true
                    return true
                } else logger.error("BASS_ChannelPlay failed for filehandle $filehandle, code ${bass.BASS_ErrorGetCode()}")
            } else logger.error("BASS_OPUS_StreamCreate failed, code ${bass.BASS_ErrorGetCode()}")
        } else logger.error("Error initializing device $deviceID with sampling rate $samplingrate, code ${bass.BASS_ErrorGetCode()}")

        return false
    }

    /**
     * Stops the Opus stream playback and frees the resources.
     */
    fun Stop(){
        if (filehandle!=0){
            bass.BASS_ChannelFree(filehandle)
            filehandle = 0
        }
        isPlaying = false
        AudioUtility.Free()
    }

    /**
     * Pushes audio data to the Opus stream for playback.
     */
    fun PushData(data: ByteArray): Boolean {
        if (filehandle == 0 || !isPlaying) return false
        if (data.isEmpty()) return false
        val buffer = Memory(data.size.toLong())
        buffer.write(0, data, 0, data.size)
        val result = bassopus.BASS_OPUS_StreamPutData(filehandle, buffer, data.size)
        if (result>=0){
            return true
        } else {
            logger.error("PushData failed, error code: ${bass.BASS_ErrorGetCode()}")
            return false
        }
    }
}