package de.yannicpunktdee.yoshibot.utils;

import de.yannicpunktdee.yoshibot.main.YoshiBot;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.TextChannel;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public class SauceProvider {
	
	private static final String BASE_URL = "https://r34-json.herokuapp.com/";
	
	private int lastKnownSauce = -1;
	
	private boolean isSauceInit = false;
	
	private static MessageEmbed notFoundEmbed = null;
	
	public SauceProvider(int timer) {
		this();
		ScheduledExecutorService sauceScheduler = Executors.newScheduledThreadPool(1);
		sauceScheduler.scheduleAtFixedRate(this::provideSauce, 0, timer, TimeUnit.SECONDS);
		new Thread(this::initSauceProviding).start();
	}
	
	public SauceProvider() {
		if (lastKnownSauce == -1) {
			this.lastKnownSauce = this.getNewestIndex();
		}
	}
	
	public static MessageEmbed getSauce(int index) {
		String url = BASE_URL + "posts?id=" + index;
		JSONObject base = getParsedSauceData(url);
		if (base.getInt("count") == 0) {
			return getNotFoundEmbed();
		}
		JSONObject post = base.getJSONArray("posts").getJSONObject(0);
		return makeStringFromJson(post);
	}
	
	public static MessageEmbed getRandomSauce(String tags) {
		tags = tagsForRest(tags);
		tags += "+" + String.join("+", Resources.getFilteredTags());
		Random rand = YoshiBot.getInstance().getRandom();
		String url = BASE_URL + "posts?tags=" + String.join("+", tags);
		Logger.logInfo("Soße angefordert für tags " + tags);
		JSONObject baseObj = getParsedSauceData(url);
		int amount = baseObj.getInt("count");
		if (amount == 0) {
			return getNotFoundEmbed();
		}
		int selectedIndex = rand.nextInt(amount);
		int page = (selectedIndex / 100) % 100;
		int pageIndex = selectedIndex % 100;
		String pagedUrl = url + "&pid=" + page;
		JSONObject post = Objects.requireNonNull(getParsedSauceData(pagedUrl)).getJSONArray("posts")
				.getJSONObject(pageIndex);
		return makeStringFromJson(post);
	}
	
	private static MessageEmbed makeStringFromJson(JSONObject post) {
		EmbedBuilder eb = new EmbedBuilder();
		eb.setTitle("Soße").setDescription("URL: " + post.getString("file_url").substring(42));
		eb.addField("ID", post.getString("id"), false);
		eb.addField("Tags", "`" + post.getJSONArray("tags").join("` `") + "`", false);
		eb.setImage(post.getString("file_url").substring(42));
		
		return eb.build();
	}
	
	private void provideSauce() {
		if (!isSauceInit) return;
		for (Map.Entry<String, List<String>> feed : Resources.getFeedDetails().entrySet()) {
			String url = BASE_URL + "posts?tags=" + String.join("+", feed.getValue())
						 + "+" + String.join("+", Resources.getFilteredTags());
			JSONArray posts = getParsedSauceData(url).getJSONArray("posts");
			assert posts != null;
			List<JSONObject> postsInternal =
					StreamSupport.stream(posts.spliterator(), false)
							.map(obj -> (JSONObject) obj)
							.filter(obj -> obj.getInt("id") > lastKnownSauce)
							.collect(Collectors.toList());
			Collections.reverse(postsInternal);
			YoshiBot yoshiBot = YoshiBot.getInstance();
			for (JSONObject post : postsInternal) {
				List<TextChannel> channels = yoshiBot.jda.getTextChannelsByName(feed.getKey(), true);
				if (channels.size() == 0) {
					Logger.logError("Kein Kanal mit dem Namen " + feed.getKey() + "gefunden");
					break;
				} else if (!channels.get(0).isNSFW()) {
					Logger.logError("Kanal " + feed.getKey() + " ist nicht als NSFW markiert!");
					break;
				}
				channels.get(0).sendMessage(makeStringFromJson(post)).queue();
			}
			if (postsInternal.size() > 0) {
				Logger.logInfo(String.format("Found %d posts for feed '%s'", postsInternal.size(), feed.getKey()));
			}
			
		}
		lastKnownSauce = this.getNewestIndex();
	}
	
	private void initSauceProviding() {
		YoshiBot yoshiBot = YoshiBot.getInstance();
		try {
			yoshiBot.jda.awaitReady();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		for (Map.Entry<String, List<String>> entry : Resources.getFeedDetails().entrySet()) {
			List<TextChannel> channels = yoshiBot.jda.getTextChannelsByName(entry.getKey(), true);
			if (channels.size() > 0) {
				this.isSauceInit = true;
				this.provideSauce();
			} else {
				Logger.logError("Konnte keine Kanaäle finden für die Soße");
			}
		}
	}
	
	private int getNewestIndex() {
		JSONObject result = getParsedSauceData("https://r34-json.herokuapp.com/posts?limit=1&q=index");
		return result.getJSONArray("posts").getJSONObject(0).getInt("id");
	}
	
	private static JSONObject getParsedSauceData(String url) {
		String raw = RestHelper.getFromURL(url);
		return new JSONObject(raw);
	}
	
	private static String tagsForRest(String tags) {
		tags = tags.replace(" ", "+");
		return tags;
	}
	
	private static MessageEmbed getNotFoundEmbed() {
		if (SauceProvider.notFoundEmbed == null) {
			EmbedBuilder eb = new EmbedBuilder();
			eb.setTitle("Could not find any posts matching the filter!");
			SauceProvider.notFoundEmbed = eb.build();
		}
		return SauceProvider.notFoundEmbed;
	}
	
}
