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;

/**
 * Holder for both the player and a track scheduler for one guild.
 */
public class GuildMusicManager {
  /**
   * Audio player for the guild.
   */
  public final AudioPlayer player;
  /**
   * Track scheduler for the 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 {
		  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;
  }

  /**
   * Creates a player and a track scheduler.
   * @param manager Audio player manager to use for creating the player.
   */
  public GuildMusicManager(Guild guild, AudioTrackHandler handler, AudioPlayerManager manager) {
    player = manager.createPlayer();
    scheduler = new TrackScheduler(guild, handler, player);
    player.addListener(scheduler);
    player.setFilterFactory(equalizer);
  }

  /**
   * @return Wrapper around AudioPlayer to use it as an AudioSendHandler.
   */
  public AudioPlayerSendHandler getSendHandler() {
    return new AudioPlayerSendHandler(player);
  }
}