package xyz.alexcrea.cuanvil.gui.config.list;

import com.github.stefvanschie.inventoryframework.gui.GuiItem;
import com.github.stefvanschie.inventoryframework.gui.type.util.Gui;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.alexcrea.cuanvil.config.ConfigHolder;
import xyz.alexcrea.cuanvil.gui.config.ask.SelectItemTypeGui;
import xyz.alexcrea.cuanvil.gui.config.global.UnitRepairConfigGui;
import xyz.alexcrea.cuanvil.gui.config.list.elements.ElementMappedToListGui;
import xyz.alexcrea.cuanvil.gui.config.settings.DoubleSettingGui;
import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems;
import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant;
import xyz.alexcrea.cuanvil.util.CasedStringUtil;
import xyz.alexcrea.cuanvil.util.MaterialUtil;

import java.util.*;
import java.util.function.Consumer;

public class UnitRepairElementListGui extends SettingGuiListConfigGui<NamespacedKey, DoubleSettingGui.DoubleSettingFactory> implements ElementMappedToListGui {

    private final NamespacedKey parentMaterial;
    private final UnitRepairConfigGui parentGui;
    private final String materialName;

    private boolean shouldWork = true;

    public UnitRepairElementListGui(@NotNull NamespacedKey parentMaterial,
                                    @NotNull UnitRepairConfigGui parentGui) {
        super("§e" + CasedStringUtil.snakeToUpperSpacedCase(parentMaterial.getKey().toLowerCase()) + " §rUnit repair");
        this.parentMaterial = parentMaterial;
        this.parentGui = parentGui;
        this.materialName = CasedStringUtil.snakeToUpperSpacedCase(parentMaterial.getKey().toLowerCase());

        GuiGlobalItems.addBackItem(this.backgroundPane, parentGui);
    }

    // SettingGuiListConfigGui methods
    @Override
    protected List<String> getCreateItemLore() {
        return Arrays.asList(
                "§7Select a new item to be repairable.",
                "§7You will be asked the material to use."
        );
    }

    @Override
    protected Consumer<InventoryClickEvent> getCreateClickConsumer() {
        return event -> {
            event.setCancelled(true);
            if (!this.shouldWork) {
                return;
            }
            event.setCancelled(true);

            new SelectItemTypeGui(
                    "Select item to be repaired.",
                    "§7Click here with an item to set the item\n" +
                            "§7You like to be repaired by " + this.materialName,
                    this,
                    (itemStack, player) -> {
                        ItemMeta meta = itemStack.getItemMeta();
                        NamespacedKey type = MaterialUtil.INSTANCE.getCustomType(itemStack);

                        if (!(meta instanceof Damageable)) {
                            player.sendMessage("§cThis item can't be damaged, so it can't be repaired.");
                            return;
                        }
                        if (type.equals(this.parentMaterial)) {
                            player.sendMessage("§cItem can't repair something of the same type.");
                            return;
                        }

                        String materialName = type.toString();

                        // Add new material
                        ConfigHolder.UNIT_REPAIR_HOLDER.getConfig().set(parentMaterial.toString().toLowerCase() + "." + materialName, 0.25);

                        if (GuiSharedConstant.TEMPORARY_DO_SAVE_TO_DISK_EVERY_CHANGE) {
                            ConfigHolder.UNIT_REPAIR_HOLDER.saveToDisk(GuiSharedConstant.TEMPORARY_DO_BACKUP_EVERY_SAVE);
                        }

                        // Update gui
                        updateValueForGeneric(type, true);
                        this.parentGui.updateValueForGeneric(this.parentMaterial, true);


                        // Display material edit setting
                        this.factoryMap.get(materialName).create().show(player);
                    },
                    true
            ).show(event.getWhoClicked());

        };
    }

    @Override
    protected String createItemName() {
        return "§aAdd a new item reparable by " + this.materialName;
    }

    @Override
    protected DoubleSettingGui.DoubleSettingFactory createFactory(NamespacedKey materialName) {
        String materialDisplayName = CasedStringUtil.snakeToUpperSpacedCase(materialName.getKey());

        return new DoubleSettingGui.DoubleSettingFactory(
                "§0%§8" + materialDisplayName + " Repair",
                this,
                ConfigHolder.UNIT_REPAIR_HOLDER,
                this.parentMaterial.toString().toLowerCase() + "." + materialName,
                Arrays.asList(
                        "§7Click here to change how many §e% §7of §a" + materialDisplayName,
                        "§7Should get repaired by §e" + this.materialName
                ),
                2,
                true, true,
                0,
                1,
                0.25,
                0.01, 0.05, 0.25
        );
    }

    @Override
    protected GuiItem itemFromFactory(NamespacedKey materialName, DoubleSettingGui.DoubleSettingFactory factory) {
        return factory.getItem(materialFromName(materialName),
                "§7%§a" + CasedStringUtil.snakeToUpperSpacedCase(materialName.getKey()) + " §erepaired by §a" + this.materialName);
    }

    @Override
    protected Collection<NamespacedKey> getEveryInstanceOfGeneric() {
        Set<NamespacedKey> keys = new HashSet<>();
        if (!this.shouldWork) {
            return keys;
        }

        ConfigurationSection legacySection = ConfigHolder.UNIT_REPAIR_HOLDER.getConfig().getConfigurationSection(parentMaterial.getKey().toLowerCase());
        ConfigurationSection materialSection = ConfigHolder.UNIT_REPAIR_HOLDER.getConfig().getConfigurationSection(parentMaterial.toString().toLowerCase());

        addAllKeys(legacySection, keys);
        addAllKeys(materialSection, keys);

        return keys;
    }

    private void addAllKeys(@Nullable ConfigurationSection section, @NotNull Set<NamespacedKey> keys) {
        if (section == null) return;
        for (var key : section.getKeys(false)) {
            var material = NamespacedKey.fromString(key);
            if (material == null) continue;

            keys.add(material);
        }
    }

    private Material materialFromName(NamespacedKey material) {
        Material mat = MaterialUtil.INSTANCE.getMatFromKey(material);
        if (mat == null || mat.isAir()) return Material.BARRIER;
        return mat;
    }

    @Override
    public void updateGuiValues() {
        super.updateGuiValues();
        this.parentGui.updateValueForGeneric(this.parentMaterial, true);
    }

    // ElementMappedToListGui methods

    @Override // Not used in this implementation
    public void updateLocal() {
    }

    @Override
    public void cleanAndBeUnusable() {
        this.shouldWork = false;
        this.backgroundPane.bindItem('S', GuiGlobalItems.backgroundItem(Material.BLACK_STAINED_GLASS_PANE));
        this.backgroundPane.bindItem('L', GuiGlobalItems.backgroundItem(Material.BLACK_STAINED_GLASS_PANE));
        this.backgroundPane.bindItem('R', GuiGlobalItems.backgroundItem(Material.BLACK_STAINED_GLASS_PANE));

        for (HumanEntity viewer : getViewers()) {
            viewer.sendMessage("This config do not exist anymore");
            this.parentGui.show(viewer);
        }
    }

    @Override
    public Gui getMappedGui() {
        return this;
    }

    @Override
    public void show(@NotNull HumanEntity humanEntity) {
        if (!this.shouldWork) {
            humanEntity.closeInventory();
            return;
        }
        super.show(humanEntity);
    }

}
