package org.bukkit.craftbukkit.inventory;

import net.minecraft.world.IInventory;
import net.minecraft.world.inventory.InventoryMerchant;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.component.TypedEntityData;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTBase;

import org.bukkit.craftbukkit.util.CraftMagicNumbers;

import com.bergerkiller.bukkit.common.nbt.CommonTagCompound;

import com.bergerkiller.generated.net.minecraft.world.IInventoryHandle;
import com.bergerkiller.generated.org.bukkit.craftbukkit.inventory.CraftInventoryMerchantHandle;
import com.bergerkiller.generated.org.bukkit.craftbukkit.inventory.CraftItemStackHandle;
import com.bergerkiller.generated.net.minecraft.nbt.NBTBaseHandle;

class CraftItemStack {
    (Object) net.minecraft.world.item.ItemStack handle;

    public static (Object) net.minecraft.world.item.ItemStack asNMSCopy(org.bukkit.inventory.ItemStack original);

    public static (org.bukkit.inventory.ItemStack) CraftItemStack asCraftCopy(org.bukkit.inventory.ItemStack original);

    public static (org.bukkit.inventory.ItemStack) CraftItemStack asCraftMirror((Object) net.minecraft.world.item.ItemStack nmsItemStack);

    public static org.bukkit.inventory.meta.ItemMeta deserializeItemMeta(java.util.Map<String, Object> values) {
        return SerializableMeta.deserialize(values);
    }

#if version >= 1.21.4
    public static optional Object deserializeCustomModelData(java.util.Map<String, Object> values) {
        return new org.bukkit.craftbukkit.inventory.components.CraftCustomModelDataComponent(values);
    }
#else
    public static optional Object deserializeCustomModelData:###(java.util.Map<String, Object> values);
#endif

#if version >= 1.21.5
    public static optional org.bukkit.inventory.ItemStack deserializeNBT((CommonTagCompound) NBTTagCompound nbt) {
  #if paper
        // Use Paper UnsafeValues API
        #require CraftMagicNumbers private org.bukkit.inventory.ItemStack deserializeItem(NBTTagCompound nbt);
        return CraftMagicNumbers.INSTANCE#deserializeItem(nbt);
  #else
        // Use Spigot/NMS DFU
        final int dataVersion = nbt.getIntOr("DataVersion", 0);

        com.mojang.serialization.Dynamic migratedDynamic = net.minecraft.util.datafix.DataConverterRegistry.getDataFixer().update(
                net.minecraft.util.datafix.fixes.DataConverterTypes.ITEM_STACK,
                new com.mojang.serialization.Dynamic(net.minecraft.nbt.DynamicOpsNBT.INSTANCE, nbt),
                dataVersion,
                CraftMagicNumbers.INSTANCE.getDataVersion());

        if (migratedDynamic.getValue() == null) {
            throw new IllegalArgumentException("Failed to perform data migration of itemstack");
        }

        net.minecraft.core.HolderLookup$a holderLookup = org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry();
        NBTBase migratedNBT = (NBTBase) migratedDynamic.getValue();
    #if version >= 1.21.6
        java.util.Optional itemOpt = net.minecraft.world.item.ItemStack.CODEC.parse(
                holderLookup.createSerializationContext(net.minecraft.nbt.DynamicOpsNBT.INSTANCE),
                migratedNBT
            )
            .resultOrPartial(NBTBaseHandle.createPartialErrorLogger(migratedNBT));
    #else
        java.util.Optional itemOpt = net.minecraft.world.item.ItemStack.parse(
                holderLookup,
                migratedNBT);
    #endif
        if (!itemOpt.isPresent()) {
            return null;
        }

        net.minecraft.world.item.ItemStack item = (net.minecraft.world.item.ItemStack) itemOpt.get();
        return CraftItemStack.asCraftMirror(item);
  #endif
    }
#else
    public static optional org.bukkit.inventory.ItemStack deserializeNBT:###((CommonTagCompound) NBTTagCompound nbt);
#endif

    public static boolean isCorruptedEntityTag(org.bukkit.inventory.meta.ItemMeta itemMeta) {
        // Since 1.20.5 an "id" field must be present
#if version >= 1.20.5
        if (!(itemMeta instanceof org.bukkit.craftbukkit.inventory.CraftMetaEntityTag)) {
            return false;
        }

        org.bukkit.craftbukkit.inventory.CraftMetaEntityTag craftMeta = (org.bukkit.craftbukkit.inventory.CraftMetaEntityTag) itemMeta;

  #if version >= 1.21.9 && exists org.bukkit.craftbukkit.inventory.CraftMetaEntityTag net.minecraft.world.item.component.TypedEntityData<net.minecraft.world.entity.EntityTypes<?>> entityTag;
        // Used on spigot 1.21.9+
        #require org.bukkit.craftbukkit.inventory.CraftMetaEntityTag TypedEntityData<net.minecraft.world.entity.EntityTypes<?>> entityTag;
        TypedEntityData entityTag = craftMeta#entityTag;
        return entityTag == null;
  #else
        // Paper and versions before 1.21.9 stored the nbt tag
        #require org.bukkit.craftbukkit.inventory.CraftMetaEntityTag net.minecraft.nbt.NBTTagCompound entityTag;
        net.minecraft.nbt.NBTTagCompound entityTag = craftMeta#entityTag;
        if (entityTag == null) return false;
        net.minecraft.nbt.NBTBase idTag = entityTag.get("id");
        return !(idTag instanceof net.minecraft.nbt.NBTTagString);
  #endif
#else
        return false;
#endif
    }
}

class CraftInventory extends org.bukkit.inventory.Inventory {
    public (org.bukkit.inventory.Inventory) CraftInventory((Object) IInventory nmsIInventory);

    protected final (IInventoryHandle) IInventory handleField:inventory;

    public (IInventoryHandle) IInventory getHandle:getInventory();
}

class CraftInventoryPlayer {
    public (org.bukkit.inventory.PlayerInventory) CraftInventoryPlayer((Object) net.minecraft.world.entity.player.PlayerInventory nmsPlayerInventory);
}

class CraftInventoryCrafting {
#if version >= 1.21
    public (org.bukkit.inventory.CraftingInventory) CraftInventoryCrafting((Object) net.minecraft.world.inventory.InventoryCrafting nmsInventoryCrafting, (Object) IInventory nmsResultIInventory);
#elseif version >= 1.13
    public (org.bukkit.inventory.CraftingInventory) CraftInventoryCrafting((Object) IInventory nmsInventoryCrafting, (Object) IInventory nmsResultIInventory);
#else
    public (org.bukkit.inventory.CraftingInventory) CraftInventoryCrafting((Object) net.minecraft.server.InventoryCrafting nmsInventoryCrafting, (Object) IInventory nmsResultIInventory);
#endif
}

class CraftInventoryFurnace {
    public (org.bukkit.inventory.FurnaceInventory) CraftInventoryFurnace((Object) net.minecraft.world.level.block.entity.TileEntityFurnace nmsTileEntityFurnace);
}

class CraftInventoryBrewer {
    public (org.bukkit.inventory.BrewerInventory) CraftInventoryBrewer((Object) IInventory nmsTileEntityBrewingStand);
}

class CraftInventoryMerchant {
    public static org.bukkit.inventory.MerchantInventory createNew((Object) InventoryMerchant nmsInventoryMerchant) {
#if version >= 1.14
        Object merchant = com.bergerkiller.generated.net.minecraft.world.inventory.InventoryMerchantHandle.T.merchant.get(nmsInventoryMerchant);
        return new CraftInventoryMerchant((net.minecraft.world.item.trading.IMerchant) merchant, nmsInventoryMerchant);
#else
        return new CraftInventoryMerchant(nmsInventoryMerchant);
#endif
    }
}

class CraftInventoryBeacon {

    public static org.bukkit.inventory.BeaconInventory createNew((Object) net.minecraft.world.level.block.entity.TileEntityBeacon nmsTileEntityBeacon) {
#if version >= 1.14
        return new com.bergerkiller.bukkit.common.internal.proxy.BeaconInventory_1_14(nmsTileEntityBeacon);
#else
        return new CraftInventoryBeacon(nmsTileEntityBeacon);
#endif
    }
}
