package net.filebot.ui;

import static java.util.stream.Collectors.*;
import static javax.swing.JOptionPane.*;
import static net.filebot.Logging.*;
import static net.filebot.Settings.*;
import static net.filebot.util.StringUtilities.*;
import static net.filebot.util.ui.SwingUI.*;

import java.util.List;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.stream.Stream;

import javax.swing.Icon;
import javax.swing.JOptionPane;

import net.filebot.HistorySpooler;
import net.filebot.ResourceManager;
import net.filebot.Settings;
import net.filebot.util.PreferencesMap.PreferencesEntry;

public enum SupportDialog {

	Donation {

		@Override
		String getMessage(int renameCount) {
			return String.format("<html><p style='font-size:16pt; font-weight:bold'>Thank you for using FileBot!</p><br><p>It has taken thousands of hours to develop this application. If you enjoy using it,<br>please consider making a donation. It'll help make FileBot even better!<p><p style='font-size:14pt; font-weight:bold'>You've renamed %,d files.</p><br><html>", renameCount);
		}

		@Override
		String[] getActions(boolean first) {
			if (first)
				return new String[] { "Donate! :)", "Nope! Maybe next time." };
			else
				return new String[] { "Donate again! :)", "Nope! Not this time." };
		}

		@Override
		Icon getIcon() {
			return ResourceManager.getIcon("message.donate");
		}

		@Override
		String getTitle() {
			return "Please Donate";
		}

		@Override
		public boolean feelingLucky(int sessionRenameCount, int totalRenameCount, int currentRevision, int lastSupportRevision, int supportRevisionCount) {
			// annoy users that chose not to purchase FileBot on the Store
			if (sessionRenameCount > 0 && Stream.of("Mac OS X", "Windows 10").anyMatch(Predicate.isEqual(System.getProperty("os.name")))) {
				return true;
			}

			return super.feelingLucky(sessionRenameCount, totalRenameCount, currentRevision, lastSupportRevision, supportRevisionCount);
		}

		@Override
		String getURI() {
			return getDonateURL();
		}

	},

	AppStoreReview {

		@Override
		String getMessage(int renameCount) {
			return String.format("<html><p style='font-size:16pt; font-weight:bold'>Thank you for using FileBot!</p><br><p>It has taken thousands of hours to develop this application. If you enjoy using it,<br>please consider writing a nice review on the %s.<p><p style='font-size:14pt; font-weight:bold'>You've renamed %,d files.</p><br><html>", getAppStoreName(), renameCount);
		}

		@Override
		String[] getActions(boolean first) {
			if (first)
				return new String[] { "Write a Review! :)", "Nope! Maybe next time." };
			else
				return new String[] { "Update my Review! :)", "Nope! Not this time." };
		}

		@Override
		Icon getIcon() {
			return ResourceManager.getIcon("window.icon.large");
		}

		@Override
		String getTitle() {
			return "Please write a Review";
		}

		@Override
		public boolean feelingLucky(int sessionRenameCount, int totalRenameCount, int currentRevision, int lastSupportRevision, int supportRevisionCount) {
			// ask for reviews at most once per revision
			if (currentRevision <= lastSupportRevision) {
				return false;
			}

			// ask for reviews only when a significant number of files have been processed
			if (sessionRenameCount < 5 || totalRenameCount < 5000) {
				return false;
			}

			// ask for reviews at most every once in a while
			if (Math.random() <= 0.777) {
				return false;
			}

			return super.feelingLucky(sessionRenameCount, totalRenameCount, currentRevision, lastSupportRevision, supportRevisionCount);
		}

		@Override
		String getURI() {
			return getAppStoreLink();
		}

	};

	public boolean feelingLucky(int sessionRenameCount, int totalRenameCount, int currentRevision, int lastSupportRevision, int supportRevisionCount) {
		// lucky if many files are processed in a single session
		if (sessionRenameCount >= 2000 * Math.pow(2, supportRevisionCount)) {
			return true;
		}

		// lucky if many many files have been processed over time
		if (totalRenameCount >= 2000 * Math.pow(5, supportRevisionCount)) {
			return true;
		}

		return false;
	}

	public boolean show(int totalRenameCount, boolean first) {
		String message = getMessage(totalRenameCount);
		String[] actions = getActions(first);
		JOptionPane pane = new JOptionPane(message, INFORMATION_MESSAGE, YES_NO_OPTION, getIcon(), actions, actions[0]);
		pane.createDialog(null, getTitle()).setVisible(true);

		// open URI of OK
		if (pane.getValue() == actions[0]) {
			openURI(getURI());
		}

		// don't ask again for this version regardless of user choice
		return true;
	}

	abstract String getMessage(int totalRenameCount);

	abstract String[] getActions(boolean first);

	abstract Icon getIcon();

	abstract String getTitle();

	abstract String getURI();

	public static void maybeShow() {
		try {
			PreferencesEntry<String> persistentSupportRevision = Settings.forPackage(SupportDialog.class).entry("support.revision");
			List<Integer> supportRevision = matchIntegers(persistentSupportRevision.getValue());

			int lastSupportRevision = supportRevision.stream().max(Integer::compare).orElse(0);
			int currentRevision = getApplicationRevisionNumber();

			int sessionRenameCount = HistorySpooler.getInstance().getSessionHistoryTotalSize();
			int totalRenameCount = HistorySpooler.getInstance().getPersistentHistoryTotalSize();

			// show donation / review reminders to power users
			SupportDialog dialog = isAppStore() ? AppStoreReview : Donation;

			if (dialog.feelingLucky(sessionRenameCount, totalRenameCount, currentRevision, lastSupportRevision, supportRevision.size())) {
				if (dialog.show(totalRenameCount, supportRevision.isEmpty())) {
					supportRevision = Stream.concat(supportRevision.stream(), Stream.of(currentRevision)).sorted().distinct().collect(toList());
					persistentSupportRevision.setValue(supportRevision.toString());
				}
			}
		} catch (Exception e) {
			log.log(Level.WARNING, e, e::toString);
		}
	}

}
