package de.siphalor.was.content.quest;

import de.siphalor.was.content.product.Product;
import de.siphalor.was.content.product.ProductManager;
import de.siphalor.was.content.product.ProductType;
import de.siphalor.was.util.Util;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;

/**
 * A quest generator that follows a static list of quests.
 */
public class StaticQuestGenerator implements QuestGenerator {
	/**
	 * The list of quests to follow
	 */
	@NotNull
	private final List<Quest> quests;
	/**
	 * The current index in the quest list
	 */
	private int index = 0;

	/**
	 * Constructs a new quest generator with the given quest list.
	 * @param quests The quest list to use
	 */
	public StaticQuestGenerator(@NotNull List<Quest> quests) {
		this.quests = quests;
	}

	/**
	 * Loads a new static quest generator from the given input stream. The input stream should contain CSV format.
	 * @param inputStream An input stream with csv format
	 * @param productManager The product manager to check product definitions against
	 * @return The newly loaded quest generator or <code>null</code> if the laoding failed
	 */
	@Nullable
	public static StaticQuestGenerator fromCsv(@NotNull InputStream inputStream, @NotNull ProductManager productManager) {
		BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
		String line;

		List<Quest> quests = new ArrayList<>();

		try {
			while ((line = reader.readLine()) != null) {
				try {
					String[] parts = line.split(",");
					if (parts.length >= 3) {
						Quest.Type type = Quest.Type.valueOf(parts[0].toUpperCase(Locale.ENGLISH));
						ProductType<?> productType = productManager.get(parts[1]);
						if (productType != null) {
							int reward = Integer.parseInt(parts[2]);

							Product product = productType.getProduct(Arrays.copyOfRange(parts, 3, parts.length));

							if (product != null) {
								quests.add(new Quest(type, reward, product));
							} else {
								Util.LOGGER.log(Level.WARNING, "Invalid product in quest: " + line);
							}
						} else {
							Util.LOGGER.log(Level.WARNING, "Invalid product in quest: " + line);
						}
					} else {
						Util.LOGGER.log(Level.WARNING, "Invalid line in quests file: " + line);
					}
				} catch (Exception e) {
					Util.LOGGER.log(Level.WARNING, "Failed to load quest in csv file in line: " + line);
					e.printStackTrace();
				}
			}
			return new StaticQuestGenerator(quests);
		} catch (IOException e) {
			Util.LOGGER.log(Level.WARNING, "Failed to load quest csv file:");
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Restarts this generator.
	 */
	@Override
	public void restart() {
		index = 0;
	}

	/**
	 * Gets the next quest and advances.
	 * @return The next quest
	 */
	@Override
	public Quest nextElement() {
		return quests.get(index++);
	}

	/**
	 * Gets whether there are still new quests in the list.
	 * @return Whether there are quests left
	 */
	@Override
	public boolean hasMoreElements() {
		return index < quests.size();
	}
}
