package me.despawningbone.discordbot.command.music;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ScheduledFuture;

import com.sedmelluq.discord.lavaplayer.filter.equalizer.EqualizerFactory;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;

import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.User;

/**
 * Guild object to store music specific data and audio player / scheduler;
 * Boilerplate from
 * https://github.com/sedmelluq/lavaplayer/tree/master/demo-jda/src/main/java/com/sedmelluq/discord/lavaplayer/demo/jda
 */
public class GuildMusicManager {

	public final AudioPlayer player;

	public final TrackScheduler scheduler;

	private HashMap<String, List<String>> votes = new HashMap<>();
	public ScheduledFuture<?> clearQueueCleanup = null;
	public ScheduledFuture<?> pendingCleanup = null;
	public List<AudioTrack> pending = null;
	private EqualizerFactory equalizer = new EqualizerFactory();

	public int vote(User user, String type, int req) throws UnsupportedOperationException {
		List<String> ids = votes.get(type);
		if (ids == null) ids = new ArrayList<>();
		
		if (ids.contains(user.getId()))
			throw new UnsupportedOperationException("You have already voted!");
		
		ids.add(user.getId());
		
		if (ids.size() < req) {
			votes.put(type, ids);  //actually shouldnt need to put
			return ids.size();
		} else {  //vote passed
			votes.remove(type);

			switch (type) {  //type specific cleanup stuff
			case "tracks":
				if (pendingCleanup != null) {
					pending = null;
					pendingCleanup.cancel(true);
					pendingCleanup = null;
				}
				break;
			}

			return -1;
		}

	}

	public void clearVotes(String type) {
		votes.remove(type);
	}

	public void clearAllVotes() {
		votes.clear();
	}

	public void setGain(int fromBand, Float... values) throws IllegalArgumentException {
		for (int i = fromBand; i < values.length; i++) {
			if (values[i] > 0.25) throw new IllegalArgumentException("A band's value is out of range.");
			equalizer.setGain(i, values[i]);
		}
	}

	public Float[] getCurrentGain() {
		Float[] vals = new Float[15];
		for (int i = 0; i < 15; i++) {
			vals[i] = equalizer.getGain(i);
		}
		return vals;
	}

	public Float[] setPresetGain(String name) throws IllegalArgumentException {
		Float[] preset;
		switch (name) {
		case "bassboost":
			preset = new Float[] { 0.08f, 0.06f, 0.05f, 0f, -0.03f, -0.05f, -0.07f, -0.07f, -0.07f, -0.07f, -0.07f, -0.07f, -0.07f, -0.07f, -0.07f };
			break;
		case "default":
			preset = new Float[] { 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f };
			break;
		case "rock":
			preset = new Float[] { 0.07f, 0.05f, 0.05f, -0.01f, -0.02f, -0.02f, -0.04f, -0.04f, 0.01f, 0.01f, 0.03f, 0.05f, 0.07f, 0.08f, 0.08f };
			break;
		default:
			throw new IllegalArgumentException("Unknown preset.");
		}
		for (int i = 0; i < preset.length; i++) {
			equalizer.setGain(i, preset[i]);
		}
		return preset;
	}

	//spin up a music instance for the guild
	public GuildMusicManager(Guild guild, AudioTrackHandler handler, AudioPlayerManager manager) {
		player = manager.createPlayer();
		scheduler = new TrackScheduler(guild, handler, player);
		player.addListener(scheduler);
		player.setFilterFactory(equalizer);
	}

	public AudioPlayerSendHandler getSendHandler() {
		return new AudioPlayerSendHandler(player);
	}
}