package zenith.zov.utility.game.server;

import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.Generated;
import net.minecraft.client.MinecraftClient;
import net.minecraft.component.ComponentChanges;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.MergedComponentMap;
import net.minecraft.component.type.ItemEnchantmentsComponent;
import net.minecraft.component.type.NbtComponent;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtOps;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.world.World;
import zenith.zov.base.autobuy.enchantes.Enchant;
import zenith.zov.base.autobuy.enchantes.custom.EnchantCustom;
import zenith.zov.base.autobuy.enchantes.minecraft.EnchantVanilla;
import zenith.zov.utility.mixin.accessors.ItemStackAccessor;

public final class AutoBuyUtil {
    private static Pattern patternFuntime = Pattern.compile("\\$\\s*([0-9][\\d,]*)");
    private static Pattern patternHollyWorld = Pattern.compile("Price:(?:.*?\\{\"text\":\"([\\d ]+)\")");
    private static final Map<ItemStack, NbtCompound> nbtCompoundMap = new HashMap<>();
    public static List<String> testBypass = new ArrayList<>();

    public static int getPrice(String nbt) {
        Matcher matcher = patternFuntime.matcher(nbt);
        if (matcher.find()) {
            String priceWithCommas = matcher.group(1);
            String price = priceWithCommas.replace(",", "");
            return Integer.parseInt(price);
        } else {
            matcher = patternHollyWorld.matcher(nbt);
            if (matcher.find()) {
                String amount = matcher.group(1).replaceAll(" ", "");
                return Integer.parseInt(amount);
            } else {
                return Integer.MAX_VALUE;
            }
        }
    }

    public static boolean checkDon(ItemStack itemStack) {
        return itemStack.getCustomName().getString().contains("★");
    }

    public static int getPrice(ItemStack itemStack) {
        String nbt = getNBT(itemStack);
        return getPrice(nbt);
    }

    public static String getNBT(ItemStack itemStack) {
        return getTag(itemStack).toString();
    }

    public static String getKey(ItemStack itemStack) {
        System.out.println(getNBT(itemStack));
        NbtComponent customData = (NbtComponent)itemStack.get(DataComponentTypes.CUSTOM_DATA);
        if (customData != null) {
            System.out.println(customData.getNbt().getKeys());
            System.out.println(itemStack.getItem());
            if (customData.getNbt().contains("kringeItems")) {
                NbtElement customEnchants = customData.getNbt().get("kringeItems");
                MinecraftClient.getInstance().keyboard.setClipboard(customEnchants.toString());
                return customEnchants.toString();
            }
        }

        return "";
    }

    public static NbtCompound getTag(ItemStack stack) {
        MergedComponentMap components = ((ItemStackAccessor)stack).getComponents();
        ComponentChanges changes = components.getChanges();
        World world = MinecraftClient.getInstance().world;
        return world == null
            ? new NbtCompound()
            : nbtCompoundMap.computeIfAbsent(
                stack,
                itemStack -> (NbtCompound)ComponentChanges.CODEC.encodeStart(world.getRegistryManager().getOps(NbtOps.INSTANCE), changes).getOrThrow()
            );
    }

    public static String getTagFuntimeNotTempElements(ItemStack stack) {
        MergedComponentMap components = ((ItemStackAccessor)stack).getComponents();
        ComponentChanges changes = components.getChanges();
        World world = MinecraftClient.getInstance().world;
        return world == null
            ? ""
            : nbtCompoundMap.computeIfAbsent(
                    stack,
                    itemStack -> (NbtCompound)ComponentChanges.CODEC
                            .encodeStart(world.getRegistryManager().getOps(NbtOps.INSTANCE), changes)
                            .getOrThrow()
                )
                .toString()
                .replaceAll(",?\\s*PublicBukkitValues:\\{[^}]*\\}", "")
                .replaceAll("'\\{[^']*Expires:[^']*\\}',?", "")
                .replaceAll(",?UUID:\\[I;[-0-9]+,[-0-9]+,[-0-9]+,[-0-9]+]", "")
                .replaceAll("minecraft:[0-9a-f\\-]{36}", "minecraft:UUID");
    }

    public static ArrayList<Enchant> getEnchants(ItemStack stack) {
        ArrayList<Enchant> enchantsBuy = new ArrayList<>();
        NbtComponent customData = (NbtComponent)stack.get(DataComponentTypes.CUSTOM_DATA);
        if (customData != null && customData.getNbt().contains("Enchantments", 9)) {
            NbtList customEnchants = customData.getNbt().getList("Enchantments", 10);

            for (int i = 0; i < customEnchants.size(); i++) {
                NbtCompound ench = customEnchants.getCompound(i);
                String type = ench.getString("id");
                int level = ench.getInt("lvl");
                enchantsBuy.add(new EnchantCustom(type, type, level));
            }
        }

        ItemEnchantmentsComponent enchants = stack.getEnchantments();

        for (Entry<RegistryEntry<Enchantment>> entry : enchants.getEnchantmentEntries()) {
            String id = ((RegistryKey)((RegistryEntry)entry.getKey()).getKey().get()).getValue().toString();
            enchantsBuy.add(new EnchantVanilla(id, id, entry.getIntValue()));
        }

        return enchantsBuy;
    }

    public static boolean isAuction(ScreenHandler handledScreen) {
        return handledScreen.slots.size() == 90 && handledScreen.getSlot(49).getStack().getItem() == Items.NETHER_STAR;
    }

    public static boolean isWaitBuy(ScreenHandler handledScreen) {
        return handledScreen.slots.size() == 63 && handledScreen.getSlot(0).getStack().getItem() == Items.LIME_STAINED_GLASS_PANE;
    }

    public static void test(int slotId) {
    }

    @Generated
    private AutoBuyUtil() {
        throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
    }
}
