/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.bausystem.features.gui.editor;

import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.gui.BauGUI;
import de.steamwar.bausystem.linkage.BauGuiItem;
import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import de.steamwar.inventory.SWListInv;
import de.steamwar.linkage.Linked;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;

import java.util.*;

@Linked
public class BauGuiEditor implements Listener {

    @Getter
    private static final List<Player> open_Edits = new ArrayList<>();

    public static void openGuiEditor(Player p, ItemStack cursor) {
        BauGuiMapping mapping = BauGuiMapping.getGuiMapping(p);
        Inventory inv = Bukkit.createInventory(null, mapping.getSize() + 9, BauSystem.MESSAGE.parse("GUI_EDITOR_TITLE", p));
        for (Map.Entry<Integer, Integer> e : mapping.getMapping().entrySet()) {
            if (e.getValue() >= 0) {
                if (e.getValue() < mapping.getSize()) {
                    inv.setItem(e.getValue(), addId(BauGUI.getITEMS().get(e.getKey()).getItem(p), e.getKey()));
                }
            }
        }

        for (int j = mapping.getSize(); j < mapping.getSize() + 9; j++) {
            inv.setItem(j, new SWItem(Material.WHITE_STAINED_GLASS_PANE, "").getItemStack());
        }

        inv.setItem(mapping.getSize() + 3, new SWItem(mapping.getSize() == 9 * 5 ? Material.GRAY_STAINED_GLASS_PANE : Material.LIME_STAINED_GLASS_PANE, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_ROW_P", p)).getItemStack());
        inv.setItem(mapping.getSize() + 2, new SWItem(mapping.getSize() == 9 ? Material.GRAY_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_ROW_M", p)).getItemStack());

        inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> {
        }).getItemStack());
        inv.setItem(mapping.getSize() + 6, new SWItem(Material.TURTLE_SCUTE, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
        inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).setCustomModelData(CMDs.BACK).getItemStack());

        p.openInventory(inv);
        p.getOpenInventory().setCursor(cursor == null ? new SWItem().getItemStack() : cursor);
        open_Edits.add(p);
        BauGuiMapping.startWatchdog();
    }

    private static ItemStack addId(ItemStack itemStack, int id) {
        ItemMeta meta = itemStack.getItemMeta();
        meta.getPersistentDataContainer().set(new NamespacedKey(BauSystem.getInstance(), "gui-item-id"), PersistentDataType.INTEGER, id);
        itemStack.setItemMeta(meta);
        return itemStack;
    }

    private static int getId(ItemStack itemStack) {
        ItemMeta meta = itemStack.getItemMeta();
        return meta.getPersistentDataContainer().get(new NamespacedKey(BauSystem.getInstance(), "gui-item-id"), PersistentDataType.INTEGER);
    }

    @EventHandler
    public void onInventoryClick(InventoryClickEvent event) {
        if (!open_Edits.contains(event.getWhoClicked())) {
            return;
        }

        ItemStack i = event.getCurrentItem();
        Player p = (Player) event.getWhoClicked();
        BauGuiMapping mapping = BauGuiMapping.getGuiMapping(p);
        if (event.getClickedInventory() == p.getInventory()) {
            event.setCancelled(true);
        }

        if (event.getHotbarButton() != -1) {
            event.setCancelled(true);
        }

        if (i == null) {
            return;
        }

        if (event.getSlot() - mapping.getSize() >= 0) {
            event.setCancelled(true);
        }

        switch (event.getSlot() - mapping.getSize()) {
            case 2:
                if (mapping.getSize() == 9) {
                    return;
                }
                saveMapping(p);
                mapping.setSize(mapping.getSize() - 9);
                openGuiEditor(p, event.getCursor());
                break;
            case 3:
                if (mapping.getSize() == 9 * 5) {
                    return;
                }
                saveMapping(p);
                mapping.setSize(mapping.getSize() + 9);
                openGuiEditor(p, event.getCursor());
                break;
            case 5:
                event.getView().setCursor(new SWItem().getItemStack());
                break;
            case 6:
                saveMapping(p);
                List<SWListInv.SWListEntry<BauGuiItem>> items = new ArrayList<>();
                for (BauGuiItem item : BauGUI.getITEMS().values()) {
                    if (mapping.isShown(item.getId())) {
                        continue;
                    }
                    SWItem ip = new SWItem();
                    ip.setItemStack(item.getItem(p));
                    items.add(new SWListInv.SWListEntry(ip, item));
                }
                if (items.isEmpty()) {
                    return;
                }
                SWListInv<BauGuiItem> inv = new SWListInv<>(p, BauSystem.MESSAGE.parse("GUI_EDITOR_TITLE_MORE", p), items, (clickType, item) -> {
                    openGuiEditor(p, addId(item.getItem(p), item.getId()));
                });
                inv.open();
                break;
            case 8:
                saveMapping(p);
                BauGUI.openBauGui(p);
                break;
            default:
        }
    }

    @EventHandler
    public void onEntityDamage(EntityDamageEvent event) {
        if (open_Edits.contains(event.getEntity())) {
            event.setCancelled(true);
        }
    }

    @EventHandler
    public void onPlayerMove(PlayerMoveEvent event) {
        if (open_Edits.contains(event.getPlayer())) {
            event.setCancelled(true);
        }
    }

    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent event) {
        open_Edits.remove(event.getPlayer());
    }

    @EventHandler
    public void onInventoryDrag(InventoryDragEvent event) {
        if (open_Edits.contains(event.getWhoClicked())) {
            if (event.getRawSlots().stream().anyMatch(integer -> event.getView().getInventory(integer) == event.getWhoClicked().getInventory())) {
                event.setCancelled(true);
            }
        }
    }

    private void saveMapping(Player p) {
        saveMapping(p.getOpenInventory(), BauGuiMapping.getGuiMapping(p));
    }

    private void saveMapping(InventoryView view, BauGuiMapping mapping) {
        if (mapping.isSaved()) {
            return;
        }
        HashMap<Integer, Integer> newMapping = new HashMap<>();

        for (int i = 0; i < view.getTopInventory().getContents().length; i++) {
            ItemStack itemStack = view.getTopInventory().getContents()[i];
            if (itemStack == null || itemStack.getType() == Material.AIR || i >= mapping.getSize()) continue;
            newMapping.put(getId(itemStack), i);
        }

        for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
            if (!newMapping.containsKey(e.getKey())) {
                newMapping.put(e.getKey(), -1);
            }
        }

        mapping.setMapping(newMapping);
        mapping.save();
    }

    @EventHandler
    public void onInventoryClose(InventoryCloseEvent event) {
        if (!open_Edits.contains(event.getPlayer())) {
            return;
        }

        Player p = (Player) event.getPlayer();

        saveMapping(event.getView(), BauGuiMapping.getGuiMapping(p));
        open_Edits.remove(p);
    }
}
