package ru.redguy.qseller;

import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.material.MaterialData;
import org.ipvp.canvas.ClickInformation;
import org.ipvp.canvas.Menu;
import org.ipvp.canvas.slot.Slot;
import org.ipvp.canvas.type.ChestMenu;

import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class QSellerMenu {

    Menu menu;

    /**
     * Removes the items of type from an inventory.
     * @param inventory Inventory to modify
     * @param type The type of Material to remove
     * @param amount The amount to remove, or Integer.MAX_VALUE to remove all
     * @return The amount of items that could not be removed, 0 for success, or -1 for failures
     */
    public static int removeItems(Inventory inventory, Material type, short meta, int amount) {

        if(type == null || inventory == null)
            return -1;
        if (amount <= 0)
            return -1;

        if (amount == Integer.MAX_VALUE) {
            inventory.remove(type);
            return 0;
        }

        HashMap<Integer,ItemStack> retVal = inventory.removeItem(new ItemStack(type,amount,meta));

        int notRemoved = 0;
        for(ItemStack item: retVal.values()) {
            notRemoved+=item.getAmount();
        }
        return notRemoved;
    }

    public void sell(Player player, ClickInformation info) {
        ItemStack item = info.getClickedSlot().getItem(player);
        if(player.getInventory().contains(new ItemStack(item.getType(),item.getType().getMaxStackSize(),item.getData().getData()))) {
            Optional<SellItem> items = QSeller.getInstance().getSellItemList("game.menu.items").stream().filter(i -> item.getType().equals(i.getItem())&&i.getMeta()==item.getData().getData()).findFirst();
            if(items.isPresent()) {
                int startStacks = QSeller.getInstance().getInt("game.menu.startStacks");
                int step = QSeller.getInstance().getInt("game.menu.step");
                int villagerLevel = Database.getInstance().getVillagerLevel(player.getUniqueId());
                SellItem sellItem = items.get();
                Database.getInstance().progressItem(player.getUniqueId(), item.getType());
                removeItems(player.getInventory(), item.getType(), (short) sellItem.getMeta(), item.getType().getMaxStackSize());
                double price = countPrice(player,sellItem,villagerLevel,startStacks, step);
                QSeller.getInstance().econ.depositPlayer(player, price);
                player.sendMessage(QSeller.getInstance().getParsedString("messages.sold", player).replaceAll("\\{\\{price}}",String.valueOf(price)));

                checkForNewLevel(player,villagerLevel,startStacks, step);

                render(player);
                menu.update(player);
            }
        } else {
            player.sendMessage(QSeller.getInstance().getParsedString("messages.notEnoughItems", player));
        }
    }

    private double countPrice(Player player, SellItem sellItem, int villagerLevel, int startStacks, int step) {
        int progress = Database.getInstance().getItemProgress(player.getUniqueId(),sellItem.getItem());
        return Math.max(sellItem.getHighPrice()+villagerLevel-1-progress, sellItem.getBasePrice());
    }

    private void checkForNewLevel(Player player,int villagerLevel, int startStacks, int step) {
        if(QSeller.getInstance().getInt("game.menu.maxVillagerLevel")<=villagerLevel) return;
        for (SellItem sellItem : QSeller.getInstance().getSellItemList("game.menu.items")) {
            int progress = Database.getInstance().getItemProgress(player.getUniqueId(),sellItem.getItem());
            int maxProgress = startStacks+(villagerLevel-1)*step;
            if(progress<maxProgress) return;
        }
        Database.getInstance().progressVillager(player.getUniqueId());
        Menu oldMenu = menu;
        menu = ChestMenu.builder(6)
                .title(QSeller.getInstance().getParsedString("game.menu.title", player))
                .build();
        render(player);
        oldMenu.close();
        menu.open(player);
    }

    private void render(Player player) {
        int i = 0;
        int item = 0;
        int villagerLevel = Database.getInstance().getVillagerLevel(player.getUniqueId());
        int startStacks = QSeller.getInstance().getInt("game.menu.startStacks");
        int step = QSeller.getInstance().getInt("game.menu.step");
        List<SellItem> items = QSeller.getInstance().getSellItemList("game.menu.items");
        for (char ch : String.join("", QSeller.getInstance().getStringList("game.menu.structure")).toCharArray()) {
            Slot slot = menu.getSlot(i);
            ItemStack stack;
            ItemMeta meta;

            switch (ch) {
                case '#':
                    stack = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) QSeller.getInstance().getInt("game.menu.backgroundColor"));
                    meta = stack.getItemMeta();
                    meta.setLocalizedName(" ");
                    stack.setItemMeta(meta);

                    slot.setItem(stack);
                    break;
                case 'b':
                    stack = new ItemStack(Material.SIGN);
                    meta = stack.getItemMeta();
                    meta.setLocalizedName(QSeller.getInstance().getParsedString("game.menu.info.tittle", player));
                    meta.setLore(QSeller.getInstance().getParsedStringList("game.menu.info.lore", player));
                    stack.setItemMeta(meta);

                    slot.setItem(stack);
                    break;
                case 'i':
                    if (item < items.size()) {
                        SellItem sellItem = items.get(item);
                        stack = new ItemStack(sellItem.getItem(),1, (byte) sellItem.getMeta());
                        if(stack.getType().equals(Material.AIR)) {
                            item++;
                            break;
                        }
                        meta = stack.getItemMeta();
                        meta.setLore(
                                QSeller.getInstance().getParsedStringList("game.menu.item.lore", player).stream()
                                        .map(str -> str.replaceAll("\\{\\{price}}", String.valueOf(countPrice(player,sellItem,villagerLevel,startStacks, step))))
                                        .map(str -> str.replaceAll("\\{\\{min_price}}", String.valueOf(sellItem.getBasePrice()+villagerLevel-1)))
                                        .map(str -> str.replaceAll("\\{\\{progress_cur}}", String.valueOf(Database.getInstance().getItemProgress(player.getUniqueId(),stack.getType()))))
                                        .map(str -> str.replaceAll("\\{\\{progress_max}}", String.valueOf(startStacks+(villagerLevel-1)*step)))
                                        .collect(Collectors.toList())
                        );
                        stack.setItemMeta(meta);

                        slot.setItem(stack);
                        slot.setClickHandler(this::sell);
                    } else {
                        stack = new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 8);
                        meta = stack.getItemMeta();
                        meta.setLocalizedName(" ");
                        stack.setItemMeta(meta);

                        slot.setItem(stack);
                    }
                    item++;
                    break;
            }
            i++;
        }
    }

    public void open(Player player) {
        menu = ChestMenu.builder(6)
                .title(QSeller.getInstance().getParsedString("game.menu.title", player))
                .build();
        render(player);
        menu.open(player);
    }
}
