package com.avairebot.orion.audio;

import com.avairebot.orion.factories.MessageFactory;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
import net.dv8tion.jda.core.entities.User;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * This class schedules tracks for the audio player. It contains the queue of tracks.
 */
public class TrackScheduler extends AudioEventAdapter {

    private final GuildMusicManager manager;
    private final AudioPlayer player;
    private final BlockingQueue<AudioTrackContainer> queue;

    private AudioTrackContainer audioTrackContainer;

    /**
     * @param manager The guild music manager.
     * @param player  The audio player this scheduler uses.
     */
    public TrackScheduler(GuildMusicManager manager, AudioPlayer player) {
        this.manager = manager;
        this.player = player;
        this.queue = new LinkedBlockingQueue<>();
    }

    /**
     * Add the next track to queue or play right away if nothing is in the queue.
     *
     * @param track     The track to play or add to queue.
     * @param requester The user who requested the audio track.
     */
    public void queue(AudioTrack track, User requester) {
        // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If
        // something is playing, it returns false and does nothing. In that case the player was already playing so this
        // track goes to the queue instead.
        AudioTrackContainer container = new AudioTrackContainer(track, requester);

        if (!player.startTrack(track, true)) {
            queue.offer(container);
            return;
        }

        if (manager.getLastActiveMessage() != null) {
            audioTrackContainer = container;
            sendNowPlaying(container);
        }
    }

    /**
     * Start the next track, stopping the current one if it is playing.
     */
    public void nextTrack() {
        // Start the next track, regardless of if something is already playing or not. In case queue was empty, we are
        // giving null to startTrack, which is a valid argument and will simply stop the player.
        AudioTrackContainer container = queue.poll();

        if (container == null) {
            player.startTrack(null, false);
            return;
        }

        audioTrackContainer = container;
        player.startTrack(container.getAudioTrack(), false);
        if (manager.getLastActiveMessage() != null) {
            sendNowPlaying(container);
        }
    }

    @Override
    public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
        if (endReason.mayStartNext) {
            if (manager.isRepeatQueue()) {
                queue.offer(new AudioTrackContainer(track.makeClone(), getAudioTrackContainer().getRequester()));
            }

            nextTrack();
            return;
        }

        if (endReason.equals(AudioTrackEndReason.FINISHED) && queue.isEmpty()) {
            if (manager.getLastActiveMessage() != null) {
                MessageFactory.makeSuccess(manager.getLastActiveMessage(), "Queue has ended, leaving voice.").queue();
                manager.getLastActiveMessage().getGuild().getAudioManager().closeAudioConnection();
            }
        }
    }

    public BlockingQueue<AudioTrackContainer> getQueue() {
        return queue;
    }

    public AudioTrackContainer getAudioTrackContainer() {
        return audioTrackContainer;
    }

    private void sendNowPlaying(AudioTrackContainer container) {
        MessageFactory.makeSuccess(manager.getLastActiveMessage(), "Now playing: [:title](:link)\n`:duration` - Requested by :requester")
            .set("title", container.getAudioTrack().getInfo().title)
            .set("link", container.getAudioTrack().getInfo().uri)
            .set("duration", container.getFormattedDuration())
            .set("requester", container.getRequester().getAsMention())
            .queue();
    }
}

@@ -426,16 +426,100 @@
 gQueue;%0A
+import java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors;%0A
 import j
@@ -711,16 +711,93 @@
 pter %7B%0A%0A
+    public final ExecutorService service = Executors.newCachedThreadPool();%0A%0A
     priv
@@ -2689,32 +2689,384 @@
 k(null, false);%0A
+            if (manager.getLastActiveMessage() == null)%0A                return;%0A%0A            service.submit(() -%3E %7B%0A                MessageFactory.makeSuccess(manager.getLastActiveMessage(), %22Queue has ended, leaving voice.%22).queue();%0A%0A                manager.getLastActiveMessage().getGuild().getAudioManager().closeAudioConnection();%0A            %7D);%0A
             retu

Fix bot bot disconnecting when queue ends