package de.yannicpunktdee.yoshibot.command.commands;

import de.yannicpunktdee.yoshibot.command.YoshiCommand;
import de.yannicpunktdee.yoshibot.command.YoshiCommandContext;
import de.yannicpunktdee.yoshibot.main.YoshiBot;
import de.yannicpunktdee.yoshibot.utils.Resources;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.VoiceChannel;

import org.apache.commons.text.similarity.JaccardDistance;

import java.awt.Color;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

public class PlayCommand extends YoshiCommand {
	
	protected String[] requiredArguments = {"name"};
	
	private static final Map<User, Long> cooldownChecker = new HashMap<>();
	
	private static final int SECOND_DELAY = 5;
	
	
	public PlayCommand(YoshiCommandContext context) {
		super(context);
	}
	
	
	@Override
	public boolean execute() {
		if (!super.execute()) return false;
		
		for (User user : cooldownChecker.keySet()) {
			Long timestamp = cooldownChecker.get(user);
			if (System.currentTimeMillis() - timestamp > SECOND_DELAY * 1000) {
				cooldownChecker.remove(user);
			}
		}
		
		if (context.containsArguments(new String[]{"add", "name"})) {
			return addSound(context.getArgument("name"));
		} else if (context.containsArgument("list")) {
			return listSounds();
		} else if (context.containsArgument("name")) {
			return playSound(context.getArgument("name"));
		} else {
			context.getEvent().getMessage().getTextChannel().sendMessage("Blyat, keine Ahnung was du willst. Gib mal " +
																		 "Parameter").queue();
		}
		
		return true;
	}
	
	private boolean addSound(String filename) {
		File download = downloadAttachmentToFile(Resources.getAudioPath(), filename);
		if (download.isFile()) {
			sendInfoMessage("Audio erfolgreich hinzugefügt.");
			return true;
		} else {
			sendErrorMessage("Audio konnte nicht hinzugefügt werden.");
			return false;
		}
	}
	
	private boolean listSounds() {
		EmbedBuilder eb = new EmbedBuilder();
		eb.setTitle("Es sind folgende Audios verf\u00fcgbar:");
		eb.setColor(Color.cyan);
		eb.setDescription(String.join("\n", getAllFiles()));
		sendCustomMessage(eb.build());
		return true;
	}
	
	private boolean playSound(String requestedFile) {
		if (requestedFile == null) {
			sendErrorMessage(String.format("Konnte keine Audiodatei namens '%s.opus' finden!",
										   context.getArgument("name")));
			return false;
		}
		requestedFile = getBestMatch(requestedFile, getAllFiles());
		File file = new File(Resources.getPathToAudioFile(requestedFile));
		if (!file.isFile()) {
			sendErrorMessage(String.format("Konnte keine Audiodatei namens '%s.opus' finden!",
										   context.getArgument("name")));
			return false;
		}
		VoiceChannel vc = getVoiceChannelByParam();
		if (vc == null) {
			sendErrorMessage("Konnte keinen Audiochannel auswählen.");
			return false;
		}
		User author = context.getEvent().getAuthor();
		if (YoshiBot.getInstance().jda.getVoiceChannels().parallelStream()
				.flatMap(vcs -> vcs.getMembers().parallelStream()).map(
						Member::getUser).noneMatch(user -> user == author)) {
			if (PlayCommand.cooldownChecker.containsKey(author)) {
				sendErrorMessage(
						"Иди нахуй (geh auf Schwanz), du musst " + SECOND_DELAY + "s warten, wenn du nicht in" +
						" einem Channel bist");
				return false;
			}
			PlayCommand.cooldownChecker.put(author, System.currentTimeMillis());
		}
		context.getEvent().getMessage().getTextChannel()
				.sendMessage("Danke, " + context.getEvent().getMessage().getAuthor().getName() + ". Spiele '" +
							 requestedFile + "' in '" + vc.getName() + "' ab").queue();
		YoshiBot.getInstance().playSound(file, vc);
		return true;
	}
	
	private String getBestMatch(String word, List<String> choices) {
		Optional<String> match = choices.parallelStream().filter(word::equals).findAny();
		return match.orElse(choices.parallelStream().min(
				Comparator.comparingDouble(file -> new JaccardDistance().apply(word, file))).orElse(null));
	}
	
	private List<String> getAllFiles() {
		File audioDirectory = new File(Resources.getAudioPath());
		return Arrays.stream(Objects.requireNonNull(audioDirectory.listFiles()))
				.map(File::getName)
				.filter(name -> name.endsWith(".opus"))
				.map(name -> name.substring(0, name.lastIndexOf(".")))
				.sorted(String::compareToIgnoreCase).collect(Collectors.toList());
	}
}
