package BASS;

import lombok.Getter;
import org.tinylog.Logger;


@SuppressWarnings("unused")
public class AudioPlayer {
    private final Bass bass = Bass.Instance;
    private @Getter boolean inited = false;
    private @Getter String currentFile = "";
    private int currentFileHandle = 0;

    public void WaitUntilFinished(){
        while(currentFileHandle!=0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException ignored) {
            }
        }
    }

    public boolean isPlaying(){
        return currentFileHandle!=0;
    }

    public void StopCurrentPlayback(){
        if (currentFileHandle!=0){
            if (bass.BASS_ChannelStop(currentFileHandle)){
                Logger.info("AudioPlayer StopCurrentPlayback success");
            } else Logger.error("AudioPlayer StopCurrentPlayback failed, error code: "+bass.BASS_ErrorGetCode());
        }
        currentFileHandle = 0;
        currentFile = "";
    }

    /**
     * Initialize AudioPlayer
     * @param deviceid device id to be used, 0 = no speaker, 1 = first device, 2 ... n = other devices
     * @param samplingrate sampling rate to be used, 44100 = CD quality, 48000 = DVD quality
     */
    public AudioPlayer(int deviceid, int samplingrate){
        if (bass.BASS_GetVersion()!=0){
            if (deviceid>-1){
                int initflags = Bass.BASS_DEVICE_16BITS | Bass.BASS_DEVICE_STEREO | Bass.BASS_DEVICE_FREQ | Bass.BASS_DEVICE_REINIT;
                if (bass.BASS_Init(deviceid,samplingrate,initflags)){
                    currentFileHandle = 0;
                    inited = true;
                } else Logger.error("AudioPlayer initialization failed, BASS_Init failed, error code: " + bass.BASS_ErrorGetCode());
            } else Logger.error("AudioPlayer initialization failed, deviceid is not correct");
        } else Logger.error("AudioPlayer initialization failed, BASS version is not correct");
    }

    /**
     * Free AudioPlayer
     */
    public void Free(){
        if (inited){
            if (bass.BASS_Free()){
                Logger.info("AudioPlayer Free success");
            } else Logger.error("AudioPlayer Free failed, error code: "+bass.BASS_ErrorGetCode());
            inited = false;
        }
        currentFile = "";
        currentFileHandle = 0;
    }

    /**
     * Set Output Volume
     * @param volume volume level, 0-100
     */
    public void setOutputVolume(int volume){
        if (volume<0) volume = 0;
        if (volume>100) volume = 100;
        if (inited){
            if (!bass.BASS_SetVolume(volume/100f)){
                Logger.error("AudioPlayer SetVolume failed, error code: "+bass.BASS_ErrorGetCode());
            }
        } else Logger.info("AudioPlayer SetVolume failed, AudioPlayer is not initialized");
    }

    /**
     * Get Output Volume
     * @return volume level, 0-100
     */
    public int getOutputVolume(){
        if (inited){
            float volume = bass.BASS_GetVolume();
            if (volume>=0 && volume<=1){
                return (int)(volume*100);
            } else Logger.info("AudioPlayer GetVolume failed, volume is not correct");
        } else Logger.info("AudioPlayer GetVolume failed, AudioPlayer is not initialized");
        return -1;
    }





    /**
     * Play Audio File
     * @param filename File to be played
     * @param playbackstatus PlaybackStatus callback
     */
    public void PlayFile(final String filename, final PlaybackStatus playbackstatus){
        if (inited && filename!=null && !filename.isEmpty()){
            int filehandle = bass.BASS_StreamCreateFile(false, filename, 0, 0, 0);
            if (filehandle!=0){
                if (bass.BASS_ChannelStart(filehandle)){
                    currentFile = filename;
                    currentFileHandle = filehandle;
                    new Thread(()->{
                        if (playbackstatus!=null) playbackstatus.onPlaybackStarted(filename);
                        boolean iscontinue = true;
                        while(iscontinue){
                            switch (bass.BASS_ChannelIsActive(filehandle)) {
                                case Bass.BASS_ACTIVE_PAUSED_DEVICE :
                                    if (playbackstatus!=null) playbackstatus.onPlaybackFailure(filename);
                                    iscontinue = false;
                                    break;
                                case Bass.BASS_ACTIVE_STOPPED:
                                    iscontinue = false;
                                    break;
                                default : {
                                    try {
                                        Thread.sleep(100);
                                    } catch (InterruptedException e) {
                                        iscontinue = false;
                                    }
                                }
                            }
                        }
                        if (playbackstatus!=null) playbackstatus.onPlaybackFinished(filename);
                        currentFile = "";
                        currentFileHandle = 0;
                    }).start();
                } else {
                    Logger.error("AudioPlayer PlayFile failed, BASS_ChannelStart failed, error code: "+bass.BASS_ErrorGetCode());
                    if (playbackstatus!=null) playbackstatus.onPlaybackFailure(filename);
                }
            } else {
                Logger.error("AudioPlayer PlayFile failed, BASS_StreamCreateFile failed, error code: "+bass.BASS_ErrorGetCode());
                if (playbackstatus!=null) playbackstatus.onPlaybackFailure(filename);
            }
        } else {
            Logger.info("AudioPlayer PlayFile failed, AudioPlayer is not initialized");
            if (playbackstatus!=null) playbackstatus.onPlaybackFailure(filename);
        }
    }

}
