/*
 *   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;

import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.features.gui.editor.BauGuiMapping;
import de.steamwar.bausystem.linkage.BauGuiItem;
import de.steamwar.inventory.SWInventory;
import lombok.Getter;
import lombok.experimental.UtilityClass;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;

import java.util.*;

@UtilityClass
public class BauGUI {

    @Getter
    private static final Map<Integer, BauGuiItem> ITEMS = new HashMap<>();

    private static final Set<Player> OPEN_INVS = new HashSet<>();
    private static boolean updating = false;

    public static ItemStack getGUI_ITEM(Player p) {
        ItemStack GUI_ITEM = new ItemStack(Material.NETHER_STAR);
        ItemMeta meta = GUI_ITEM.getItemMeta();
        meta.setDisplayName(ChatColor.YELLOW + BauSystem.MESSAGE.parse("GUI_NAME", p));
        GUI_ITEM.setItemMeta(meta);
        return GUI_ITEM;
    }

    public static void addItem(BauGuiItem item) {
        if (ITEMS.containsKey(item.getId())) {
            throw new IllegalArgumentException("Duplicate Id Key: " + item.getId() + ". From Classes: " + ITEMS.get(item.getId()).getClass().getName() + " and " + item.getClass().getName());
        }
        ITEMS.put(item.getId(), item);
    }

    public static void openBauGui(Player p) {
        if (!updating) {
            OPEN_INVS.add(p);
        }
        BauGuiMapping mapping = BauGuiMapping.getGuiMapping(p);
        SWInventory inv = new SWInventory(p, mapping.getSize(), BauSystem.MESSAGE.parse("GUI_NAME", p));
        getITEMS().values().forEach(item -> {
            if (!mapping.isShown(item.getId())) {
                return;
            }

            inv.setItem(mapping.getSlot(item.getId()), permissionLore(item.getItem(p), item.permission(), p), clickType -> {
                if (item.permission().hasPermission(p)) {
                    if (item.click(clickType, p)) {
                        update();
                    }
                } else {
                    p.closeInventory();
                    BauSystem.MESSAGE.send("NO_PERMISSION", p);
                }
            });
        });
        inv.addCloseCallback(clickType -> {
            if (!updating) {
                OPEN_INVS.remove(p);
            }
        });
        inv.open();
    }

    public static void update() {
        updating = true;
        OPEN_INVS.forEach(BauGUI::openBauGui);
        updating = false;
    }

    public static void giveItem(Player p) {
        SWUtils.giveItemToPlayer(p, getGUI_ITEM(p));
    }

    private static ItemStack permissionLore(ItemStack itemStack, Permission permission, Player p) {
        ItemMeta meta = itemStack.getItemMeta();
        if (!permission.hasPermission(p)) {
            List<String> lore = meta.getLore();
            if (lore == null) {
                lore = Collections.singletonList(BauSystem.MESSAGE.parse("NO_PERMISSION", p));
            } else {
                lore.add(BauSystem.MESSAGE.parse("NO_PERMISSION", p));
            }
            meta.setLore(lore);
        }
        itemStack.setItemMeta(meta);
        return itemStack;
    }
}
