package dev.okenote.items;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import net.minestom.server.tag.Tag;

@Getter
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
public enum JediItemComponent {

    TECH_NAME("techName", String.class),
    CATEGORY("category", String.class),
    RARE("rare", String.class),
    UID("uid", Integer.class),
    LEVEL("level", Integer.class),
    OWNER("owner", String.class),
    DAMAGE("damage", Double.class),
    NODROP("nodrop", Boolean.class),
    FACTION("faction", String.class),
    MOB_KILLS("mob_kills", Integer.class),
    PLAYER_KILLS("player_kills", Integer.class),
    VAMPIRISM("vampirism", Integer.class),
    ARTEFACT("artefact", Boolean.class),
    POWER("power", Integer.class),
    BULLET("bullet", Integer.class),
    CRITICAL_DAMAGE("critical_damage", Double.class),
    CRITICAL_CHANCE("critical_chance", Double.class);

    String namespace;
    Class<?> typeClass;

    public Tag<?> getTag() {
        if (typeClass == String.class) {
            return Tag.String(namespace);
        } else if (typeClass == Integer.class) {
            return Tag.Integer(namespace);
        } else if (typeClass == Double.class) {
            return Tag.Double(namespace);
        } else if (typeClass == Boolean.class) {
            return Tag.Boolean(namespace);
        }
        return null;
    }
}

package dev.okenote.items;

import dev.okenote.JediCraft;
import dev.okenote.database.Items;
import dev.okenote.database.User;
import dev.okenote.entities.player.Faction;
import dev.okenote.entities.player.JediPlayer;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.FieldDefaults;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemComponent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.tag.Tag;

import java.util.*;
import java.util.stream.Collectors;

@Getter
public class JediItem {

    public final Tag<String> TECH_NAME = Tag.String("techName");
    public final Tag<String> CATEGORY = Tag.String("category");
    public final Tag<String> RARE = Tag.String("rare");
    public final Tag<Integer> UID = Tag.Integer("uid");
    public final Tag<Integer> LEVEL = Tag.Integer("level");
    public final Tag<String> FACTION = Tag.String("faction");
    public final Tag<String> OWNER = Tag.String("owner");
    public final Tag<Boolean> NODROP = Tag.Boolean("nodrop");
    public final Tag<Boolean> ARTEFACT = Tag.Boolean("artefact");
    public final Tag<Boolean> CAP = Tag.Boolean("cap");
    public final Tag<Integer> POWER = Tag.Integer("power");
    public final Tag<Double> VAMPIRISM = Tag.Double("vampirism");
    public final Tag<Integer> MOB_KILLS = Tag.Integer("mobKills");
    public final Tag<Integer> PLAYER_KILLS = Tag.Integer("playerKills");
    public final Tag<Double> DAMAGE = Tag.Double("damage");
    public final Tag<Double> CRITICAL_DAMAGE = Tag.Double("criticalDamage");
    public final Tag<Double> CRITICAL_CHANCE = Tag.Double("criticalChance");
    public final Tag<Integer> COOLDOWN = Tag.Integer("cooldown");

    public final Map<String, ItemStack> serverItems = new HashMap<>();

    public MetaData applyJediItem(ItemStack itemStack, String techName, Category category, Rare rare) {
        ItemStack newItemStack = itemStack.with(metaBuilder -> {
            metaBuilder.set(TECH_NAME, techName);
            metaBuilder.set(CATEGORY, category.getNamespace());
            metaBuilder.set(RARE, rare.getNamespace());
            metaBuilder.maxStackSize(100);
        });

        return new MetaData(newItemStack, techName, this);
    }

    public ItemStack activate(JediPlayer jediPlayer, ItemStack itemStack, Items.State state) {
        //TODO Сделать проверки, разделить всё такое if (!itemStack.hasTag(UID) || !itemStack.hasTag(OWNER)) return itemStack;

        if (itemStack.getTag(UID) != 0) return itemStack;

        JediCraft jediCraft = JediCraft.getJediCraft();

        int nextUid = jediCraft.getDataBaseLayer().getItemsDao().getAllCached().size() + 1;

        jediCraft.getDataBaseLayer().getItemsDao().load(nextUid, new Items(nextUid, jediPlayer, itemStack, state));

        List<Component> lore = itemStack.get(ItemComponent.LORE);

        List<Component> updatedLore;

        updatedLore = lore.stream()
                .map(component -> {
                    if (component instanceof TextComponent textComponent) {
                        String currentText = LegacyComponentSerializer.legacySection().serialize(textComponent);

                        String updatedText = currentText.replace("Владелец: null", "Владелец: " + jediPlayer.getUsername())
                                .replace("UID: 0", "UID: " + nextUid);

                        return LegacyComponentSerializer.legacySection().deserialize(updatedText);
                    }
                    return component;
                })
                .collect(Collectors.toList());

        return itemStack.with(meta -> {
            meta.setTag(UID, nextUid);
            meta.setTag(OWNER, jediPlayer.getUsername());
            meta.lore(updatedLore);
        });
    }

    public ItemStack appendLore(ItemStack itemStack, Component... lines) {
        List<Component> lore = itemStack.get(ItemComponent.LORE);
        assert lore != null;
        lore.addAll(Arrays.asList(lines));
        return itemStack.with(meta -> meta.lore(lore));
    }


    public String itemStackToString(ItemStack itemStack) {
        String techName = itemStack.getTag(TECH_NAME);
        if (techName == null) return null;

        int amount = itemStack.amount();

        StringBuilder sb = new StringBuilder();
        sb.append(techName).append(":").append(amount);

        JediItemComponent[] components;

        if (!itemStack.getTag(CATEGORY).equals(Category.SPECIAL_ITEM.getNamespace())) {
            components = new JediItemComponent[]{JediItemComponent.UID,
                    JediItemComponent.OWNER,
                    JediItemComponent.PLAYER_KILLS,
                    JediItemComponent.MOB_KILLS};
        } else {
            components = new JediItemComponent[]{JediItemComponent.POWER};
        }

        for (JediItemComponent component : components) {
            Object value = itemStack.getTag(Objects.requireNonNull(component.getTag()));
            if (value != null) sb.append(":").append(value);
            else break;
        }

        /*
              Tag<?>[] components = {
                UID, OWNER, PLAYER_KILLS, MOB_KILLS
        };

        for (Tag<?> component : components) {
            Object value = itemStack.getTag(Objects.requireNonNull(component));
            if (value != null) sb.append(":").append(value);
            else break;
        }
        */

        return sb.toString();
    }

    public ItemStack convertStringFromItemStack(String data) {
        String[] parts = data.split(":");
        if (parts.length < 2) return null;

        String techName = parts[0];
        int amount = Integer.parseInt(parts[1]);

        ItemStack itemStack = serverItems.get(techName);
        if (itemStack == null) return null;

        ItemStack newItemStack = itemStack.withAmount(amount);

        int index = 2;

        JediItemComponent[] components;

        if (!itemStack.getTag(CATEGORY).equals(Category.SPECIAL_ITEM.getNamespace())) {
            components = new JediItemComponent[]{JediItemComponent.UID,
                    JediItemComponent.OWNER,
                    JediItemComponent.PLAYER_KILLS,
                    JediItemComponent.MOB_KILLS};
        } else {
            components = new JediItemComponent[]{JediItemComponent.POWER};
        }

        for (JediItemComponent component : components) {
            if (index < parts.length) {
                String value = parts[index];
                if (value != null && !value.isEmpty()) {
                    Tag<?> tag = component.getTag();
                    newItemStack = newItemStack.with(metaBuilder -> {
                        try {
                            if (component.getTypeClass() == Integer.class) {
                                metaBuilder.set((Tag<Integer>) tag, Integer.parseInt(value));
                            } else if (component.getTypeClass() == String.class) {
                                metaBuilder.set((Tag<String>) tag, value);
                            }
                        } catch (Exception e) {/**/}
                    });
                }
                index++;
            } else break;
        }

        Integer uid = newItemStack.getTag(UID);
        String owner = newItemStack.getTag(OWNER);
        Integer playerKills = newItemStack.getTag(PLAYER_KILLS);
        Integer mobKills = newItemStack.getTag(MOB_KILLS);

        if (uid != null) return newItemStack.with(metaBuilder -> {
            List<Component> lore = itemStack.get(ItemComponent.LORE);

            List<Component> updatedLore = lore.stream()
                    .map(component -> {
                        if (component instanceof TextComponent textComponent) {
                            String currentText = LegacyComponentSerializer.legacySection().serialize(textComponent);

                            String updateText;

                            updateText = currentText.replace("UID: 0", "UID: " + uid);

                            if (itemStack.getTag(OWNER) != null)
                                updateText = currentText.replace("Владелец: null", "Владелец: " + owner)
                                        .replace("UID: 0", "UID: " + uid);
                            if (itemStack.getTag(PLAYER_KILLS) != null)
                                updateText = currentText.replace("Убито игроков: 0", "Убито игроков: " + playerKills)
                                        .replace("Владелец: null", "Владелец: " + owner)
                                        .replace("UID: 0", "UID: " + uid);
                            if (itemStack.getTag(MOB_KILLS) != null)
                                updateText = currentText.replace("Убито мобов: 0", "Убито мобов: " + mobKills)
                                        .replace("Убито игроков: 0", "Убито игроков: " + playerKills)
                                        .replace("Владелец: null", "Владелец: " + owner)
                                        .replace("UID: 0", "UID: " + uid);

                            return LegacyComponentSerializer.legacySection().deserialize(updateText);
                        }
                        return component;
                    })
                    .collect(Collectors.toList());


            metaBuilder.lore(updatedLore);
        });

        return newItemStack;
    }

    public String inventoryToString(PlayerInventory inventory) {
        StringBuilder sb = new StringBuilder();
        int size = inventory.getSize();

        for (int slot = 0; slot < size; slot++) {
            if (slot > 0) {
                sb.append("::");
            }
            ItemStack itemStack = inventory.getItemStack(slot);
            if (itemStack != null && !itemStack.isAir()) {
                String itemString = itemStackToString(itemStack);
                if (itemString != null && !itemString.isEmpty()) {
                    sb.append(itemString);
                } else {
                    sb.append(" ");
                }
            } else {
                sb.append(" ");
            }
        }
        return sb.toString();
    }

    public void loadPlayerInventory(JediPlayer player, String data) {
        String[] itemStrings = data.split("::");
        PlayerInventory inventory = player.getInventory();
        int size = inventory.getSize();

        for (int slot = 0; slot < size && slot < itemStrings.length; slot++) {
            String itemString = itemStrings[slot];
            if (itemString != null && !itemString.trim().isEmpty() && !itemString.equals(" ")) {
                ItemStack itemStack = convertStringFromItemStack(itemString);
                if (itemStack != null) {
                    inventory.setItemStack(slot, itemStack);
                } else {
                    inventory.setItemStack(slot, ItemStack.AIR);
                }
            } else {
                inventory.setItemStack(slot, ItemStack.AIR);
            }
        }
    }

    public void savePlayerInventory(JediPlayer player) {
        String inventoryData = inventoryToString(player.getInventory());

        User inventoryPlayers = player.getUser();

        inventoryPlayers.setPlayerInventory(inventoryData);
    }

    public void saveVaultInventory(JediPlayer jediPlayer, Inventory inventory) {
        String inventoryData = inventoryToString(inventory);

        User inventoryPlayers = jediPlayer.getUser();

        inventoryPlayers.setVaultInventory(inventoryData);
    }

    public void saveBackPackInventory(JediPlayer jediPlayer, Inventory inventory) {
        String inventoryData = inventoryToString(inventory);

        User inventoryPlayers = jediPlayer.getUser();

        inventoryPlayers.setBackPackInventory(inventoryData);
    }

    public String inventoryToString(Inventory inventory) {
        StringBuilder sb = new StringBuilder();

        for (int slot = 0; slot < inventory.getSize(); slot++) {
            if (slot > 0) {
                sb.append("::");
            }
            ItemStack itemStack = inventory.getItemStack(slot);
            if (itemStack != null && !itemStack.isAir()) {
                String itemString = itemStackToString(itemStack);
                if (itemString != null && !itemString.isEmpty()) {
                    sb.append(itemString);
                } else {
                    sb.append(" ");
                }
            } else {
                sb.append(" ");
            }
        }
        return sb.toString();
    }

    public void loadInventory(Inventory inventory, String data) {
        String[] itemStrings = data.split("::");

        for (int slot = 0; slot < inventory.getSize() && slot < itemStrings.length; slot++) {
            String itemString = itemStrings[slot];
            if (itemString != null && !itemString.trim().isEmpty() && !itemString.equals(" ")) {
                ItemStack itemStack = convertStringFromItemStack(itemString);
                if (itemStack != null) {
                    inventory.setItemStack(slot, itemStack);
                } else {
                    inventory.setItemStack(slot, ItemStack.AIR);
                }
            } else {
                inventory.setItemStack(slot, ItemStack.AIR);
            }
        }
    }

    @Getter
    @FieldDefaults(level = AccessLevel.PRIVATE)
    public static class MetaData {

        ItemStack itemStack;
        final String techName;
        final JediItem jediItem;

        public MetaData(ItemStack itemStack, String techName, JediItem jediItem) {
            this.techName = techName;
            this.jediItem = jediItem;

            String categoryStr = itemStack.getTag(Tag.String("category"));
            String rareStr = itemStack.getTag(Tag.String("rare"));

            Category category = Category.getByNamespace(categoryStr);
            Rare rare = Rare.getByRarity(rareStr);

            this.itemStack = itemStack.with(metaBuilder -> {
                if (category == Category.SWORD ||
                        category == Category.ABILITY ||
                        category == Category.SPECIAL_ITEM ||
                        category == Category.OTHER) {
                    metaBuilder.set(Tag.Integer(JediItemComponent.UID.getNamespace()), 1);
                }

                if (category == Category.SWORD ||
                        category == Category.ABILITY ||
                        (category == Category.SPECIAL_ITEM && rare.getWeight() >= 40) ||
                        (category == Category.OTHER && rare.getWeight() >= 35)) {
                    metaBuilder.set(Tag.String(JediItemComponent.OWNER.getNamespace()), "null");
                }

                if (category == Category.SWORD) {
                    metaBuilder.set(Tag.Integer(JediItemComponent.MOB_KILLS.getNamespace()), 0);
                    metaBuilder.set(Tag.Integer(JediItemComponent.PLAYER_KILLS.getNamespace()), 0);
                }
            });
        }

        Component name;
        final List<Component> lore = new ArrayList<>();

        public MetaData name(Component name) {
            this.name = name;
            itemStack = itemStack.withCustomName(name);
            return this;
        }

        public MetaData lore(Component lore) {
            this.lore.add(lore);
            return this;
        }

        public MetaData itemLevel(int level) {
            itemStack = itemStack.withCustomName(name.append(Component.text(" " + level + " Lvl", NamedTextColor.GOLD)));
            return this;
        }

        public MetaData textures(int id) {
            itemStack = itemStack.withCustomModelData(id);
            return this;
        }

        public MetaData nodrop() {
            itemStack = itemStack.with(metaBuilder -> metaBuilder.set(Tag.Boolean(JediItemComponent.NODROP.getNamespace()), true));
            return this;
        }

        public MetaData uid() {
            itemStack = itemStack.with(metaBuilder -> metaBuilder.set(Tag.Integer(JediItemComponent.UID.getNamespace()), 0));
            return this;
        }

        public MetaData level(int level) {
            itemStack = itemStack.with(metaBuilder -> metaBuilder.set(Tag.Integer(JediItemComponent.LEVEL.getNamespace()), level));
            return this;
        }

        public MetaData faction(Faction faction) {
            itemStack = itemStack.with(metaBuilder -> metaBuilder.set(Tag.String(JediItemComponent.FACTION.getNamespace()),
                    faction == null ? "null" : faction.name().toLowerCase()));
            return this;
        }

        public MetaData owner() {
            itemStack = itemStack.with(metaBuilder -> metaBuilder.set(Tag.String(JediItemComponent.OWNER.getNamespace()), "null"));
            return this;
        }

        public MetaData cooldown(int cooldownSeconds) {
            itemStack = itemStack.with(metaBuilder -> metaBuilder.set(Tag.Integer("cooldown"), cooldownSeconds));
            return this;
        }

        public MetaData starTrack() {
            itemStack = itemStack.with(metaBuilder -> {
                metaBuilder.set(Tag.Integer(JediItemComponent.MOB_KILLS.getNamespace()), 0);
                metaBuilder.set(Tag.Integer(JediItemComponent.PLAYER_KILLS.getNamespace()), 0);
            });
            return this;
        }

        public MetaData damage(double damage, double criticalDamage, double criticalChance) {
            itemStack = itemStack.with(metaBuilder -> {
                metaBuilder.set(Tag.Double(JediItemComponent.DAMAGE.getNamespace()), damage);
                metaBuilder.set(Tag.Double(JediItemComponent.CRITICAL_DAMAGE.getNamespace()), criticalDamage);
                metaBuilder.set(Tag.Double(JediItemComponent.CRITICAL_CHANCE.getNamespace()), criticalChance);
            });
            return this;
        }

        public void build() {
            Double damage = itemStack.getTag(Tag.Double(JediItemComponent.DAMAGE.getNamespace()));
            Double criticalChance = itemStack.getTag(Tag.Double(JediItemComponent.CRITICAL_CHANCE.getNamespace()));
            Double criticalDamage = itemStack.getTag(Tag.Double(JediItemComponent.CRITICAL_DAMAGE.getNamespace()));
            if (damage != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("⚔", NamedTextColor.RED)
                        .append(Component.text(" Урон: ", NamedTextColor.GRAY))
                        .append(Component.text(damage, NamedTextColor.AQUA, TextDecoration.BOLD)));
                lore.add(Component.text("⚡", NamedTextColor.YELLOW)
                        .append(Component.text(" Крит. урон: ", NamedTextColor.GRAY))
                        .append(Component.text(criticalDamage + " (" + criticalChance + "%)", NamedTextColor.LIGHT_PURPLE, TextDecoration.BOLD)));
            }

            Integer mobKills = itemStack.getTag(Tag.Integer(JediItemComponent.MOB_KILLS.getNamespace()));
            Integer playerKills = itemStack.getTag(Tag.Integer(JediItemComponent.PLAYER_KILLS.getNamespace()));
            if (mobKills != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("Убито мобов: " + mobKills, NamedTextColor.DARK_RED));
                lore.add(Component.text("Убито игроков: " + playerKills, NamedTextColor.DARK_RED));
            }

            Integer level = itemStack.getTag(Tag.Integer(JediItemComponent.LEVEL.getNamespace()));
            if (level != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("✓", NamedTextColor.GREEN).append(Component.text(" Требуемый уровень: ", NamedTextColor.GRAY))
                        .append(Component.text(level, NamedTextColor.GREEN, TextDecoration.BOLD)));
            }

            String faction = itemStack.getTag(Tag.String(JediItemComponent.FACTION.getNamespace()));
            if (faction != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("☬", NamedTextColor.GREEN)
                        .append(Component.text(" Доступно для " + (faction.equals("null") ? "Всех" : faction.toLowerCase()), NamedTextColor.GRAY)));
            }

            String owner = itemStack.getTag(Tag.String(JediItemComponent.OWNER.getNamespace()));
            if (owner != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("Владелец: " + owner, NamedTextColor.LIGHT_PURPLE));
            }

            Integer uid = itemStack.getTag(Tag.Integer(JediItemComponent.UID.getNamespace()));
            if (uid != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("UID: " + uid, NamedTextColor.BLUE));
            }


            String category = itemStack.getTag(Tag.String(JediItemComponent.CATEGORY.getNamespace()));
            String rare = itemStack.getTag(Tag.String(JediItemComponent.RARE.getNamespace()));
            if (category != null) {
                lore.add(Component.text("Категория: " + category));
                lore.add(Component.text("Редкость: " + rare, NamedTextColor.GRAY));
            }

            Boolean nodrop = itemStack.getTag(Tag.Boolean(JediItemComponent.NODROP.getNamespace()));
            if (nodrop != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("nodrop", NamedTextColor.LIGHT_PURPLE, TextDecoration.ITALIC));
            }

            Boolean artefact = itemStack.getTag(Tag.Boolean(JediItemComponent.ARTEFACT.getNamespace()));
            if (artefact != null) {
                lore.add(Component.text(" "));
                lore.add(Component.text("artefact", NamedTextColor.LIGHT_PURPLE, TextDecoration.ITALIC));
            }

            /*appendLore(JediCraft.getJediCraft().getChatUtil().colorize("&aПредмет можно улучшить!"));
            appendLore("&a+ " + damage + " урона");
            appendLore("&a+ " + health + " здоровья");*/

            itemStack = itemStack.withLore(lore);

            jediItem.serverItems.put(techName, itemStack);
        }
    }

    @Getter
    @AllArgsConstructor
    @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
    public enum Rare {

        DEFAULT(NamedTextColor.WHITE, "Обычный", "default", 1),
        RARE(NamedTextColor.RED, "Редкий", "rare", 10),
        EPIC(NamedTextColor.DARK_PURPLE, "Эпический", "epic", 20),
        SECRET(NamedTextColor.RED, "Тайный", "secret", 25),
        MYTHICAL(NamedTextColor.LIGHT_PURPLE, "Мифический", "mythical", 30),
        LEGENDARY(NamedTextColor.GOLD, "Легендарный", "legendary", 35),
        EXTRAORDINARY(NamedTextColor.YELLOW, "Экстраординарный", "extraordinary", 40),
        SMUGGLED(NamedTextColor.GOLD, "Контрабандный", "smuggled", 45),
        RARITY(NamedTextColor.GOLD, "Раритетный", "rarity", 50);

        NamedTextColor color;
        String rarity;
        String namespace;
        int weight;

        public Component getName() {
            return Component.text(rarity, color);
        }

        public static Rare getByRarity(String rarityStr) {
            for (Rare rare : values()) {
                if (rare.getRarity().equals(rarityStr)) {
                    return rare;
                }
            }
            return DEFAULT;
        }
    }

    @Getter
    @AllArgsConstructor
    @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
    public enum Category {

        SWORD(NamedTextColor.RED, "Оружие ближнего боя", "sword"),
        EAT(NamedTextColor.GREEN, "Еда", "eat"),
        ABILITY(NamedTextColor.AQUA, "Способность", "ability"),
        ARMOR(NamedTextColor.DARK_RED, "Броня", "armor"),
        GUN(NamedTextColor.RED, "Оружие дальнего боя", "gun"),
        ITEM(NamedTextColor.WHITE, "Обычный предмет", "item"),
        SPECIAL_ITEM(NamedTextColor.RED, "Особый предмет", "special_item"),
        OTHER(NamedTextColor.LIGHT_PURPLE, "Прочее", "other");

        NamedTextColor color;
        String typeName;
        String namespace;

        public Component getName() {
            return Component.text(typeName, color);
        }

        public static Category getByNamespace(String namespace) {
            for (Category category : values()) {
                if (category.getNamespace().equals(namespace)) {
                    return category;
                }
            }
            return null;
        }
    }
}

Привет! Удали класс JediItemComponent, вместо него используй теги в классе JediItem, улучши весь код, функциональность оставь прежней.