package audio

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import somecodes.Codes
import java.util.function.Consumer
import kotlin.io.path.absolutePathString
import kotlin.io.path.exists

/**
 * Audio Player for playing audio files.
 * Supported extensions : .wav, .mp3
 */
@Suppress("unused")
class AudioFilePlayer(deviceID: Int, val filename: String, device_samplingrate: Int = 48000) {
    private val bass: Bass = Bass.Instance
    private var filehandle = 0
    var isPlaying = false
    val fileSize: Long
    val duration: Double
    var elapsed: Double = 0.0
    init{
        val fullpath = Codes.audioFilePath.resolve(filename)
        if (fullpath.exists()){
            if (AudioUtility.InitDevice(deviceID, device_samplingrate)) {
                filehandle = bass.BASS_StreamCreateFile(false, fullpath.absolutePathString(), 0, 0, 0)
                if (filehandle!=0){
                    fileSize = bass.BASS_ChannelGetLength(filehandle, Bass.BASS_POS_BYTE)
                    duration = bass.BASS_ChannelBytes2Seconds(filehandle, fileSize)
                } else throw Exception("Failed to create stream for file $filename: ${bass.BASS_ErrorGetCode()}")

            } else throw Exception("Error initializing device $deviceID with sampling rate $device_samplingrate, code ${bass.BASS_ErrorGetCode()}")
        } else throw Exception("File $filename does not exists")

    }

    fun Stop(){
        if (filehandle!=0){
            bass.BASS_ChannelFree(filehandle)
            filehandle = 0
        }
        isPlaying = false
        AudioUtility.Free()
    }

    fun Play(finished: Consumer<Any> ) : Boolean{
        if (bass.BASS_ChannelPlay(filehandle, false)){
            elapsed = 0.0
            CoroutineScope(Dispatchers.Default).launch {
                isPlaying = true
                while(true){
                    delay(50)

                    if (bass.BASS_ChannelIsActive(filehandle)!= Bass.BASS_ACTIVE_PLAYING){
                        // finished playing
                        break
                    }
                    elapsed = bass.BASS_ChannelBytes2Seconds(filehandle, bass.BASS_ChannelGetPosition(filehandle, Bass.BASS_POS_BYTE))
                }
                isPlaying = false
                bass.BASS_ChannelFree(filehandle)
                filehandle = 0
                finished.accept(true)
            }

            return true
        }
        return false
    }
}