package net.minecraft.world.entity.ai.attributes;

import net.minecraft.resources.RegistryOps;
import net.minecraft.nbt.DynamicOpsNBT;
import net.minecraft.nbt.NBTTagList;

import com.bergerkiller.bukkit.common.nbt.CommonTagList;
import com.bergerkiller.bukkit.common.wrappers.Holder;

import com.bergerkiller.generated.net.minecraft.nbt.NBTBaseHandle;
import com.bergerkiller.generated.net.minecraft.world.entity.ai.attributes.AttributeBaseHandle;
import com.bergerkiller.generated.net.minecraft.world.entity.ai.attributes.AttributeMapBaseHandle;
import com.bergerkiller.generated.net.minecraft.world.entity.ai.attributes.AttributeModifiableHandle;

class AttributeModifiable {
#if version >= 1.20.5
    public (Holder<AttributeBaseHandle>) net.minecraft.core.Holder<AttributeBase> getAttribute();
#elseif version >= 1.16
    public (Holder<AttributeBaseHandle>) AttributeBase getAttribute();
#else
    public (Holder<AttributeBaseHandle>) IAttribute getAttribute();
#endif

#if forge_nms_obfuscated
    public abstract void setBaseValue:a(double value);
    public abstract double getBaseValue:b();
    public abstract double getValue:e();
#elseif version >= 1.18
    public abstract void setBaseValue(double value);
    public abstract double getBaseValue();
    public abstract double getValue();
#elseif version >= 1.14.4
    public abstract void setBaseValue:setValue(double value);
    public abstract double getBaseValue();
    public abstract double getValue();
#else
    public abstract void setBaseValue:setValue(double value);
    public abstract double getBaseValue:b();
    public abstract double getValue();
#endif

#if version >= 1.18
    public void removeAllModifiers:removeModifiers();
#elseif version >= 1.17
    public void removeAllModifiers:e();
#elseif version >= 1.14.4
    public void removeAllModifiers() {
        java.util.Iterator allModifiers = instance.getModifiers().iterator();
        while (allModifiers.hasNext()) {
            instance.removeModifier((AttributeModifier) allModifiers.next());
        }
    }
#else
    public void removeAllModifiers() {
        java.util.Iterator allModifiers = instance.c().iterator();
        while (allModifiers.hasNext()) {
            instance.c((AttributeModifier) allModifiers.next());
        }
    }
#endif
}

class AttributeMapBase {
#if version >= 1.16
    public (Collection<AttributeModifiableHandle>) Collection<AttributeModifiable> getAllAttributes() {
  #if version >= 1.20.5
        #require AttributeMapBase private final java.util.Map<net.minecraft.core.Holder<AttributeBase>, AttributeModifiable> attributesMap:attributes;
  #elseif version >= 1.17
        #require AttributeMapBase private final java.util.Map<AttributeBase, AttributeModifiable> attributesMap:attributes;
  #else
        #require AttributeMapBase private final java.util.Map<AttributeBase, AttributeModifiable> attributesMap:b;
  #endif
        java.util.Map attributes = instance#attributesMap;
        return attributes.values();
    }
#else
    public (Collection<AttributeModifiableHandle>) Collection<AttributeModifiable> getAllAttributes() {
        return instance.a();
    }
#endif

#if version >= 1.21
    public (Set<AttributeModifiableHandle>) Set<AttributeModifiable> getChangedSynchronizedAttributes:getAttributesToSync();
    public (Collection<AttributeModifiableHandle>) Collection<AttributeModifiable> getSynchronizedAttributes:getSyncableAttributes();
#elseif version >= 1.18
    public (Set<AttributeModifiableHandle>) Set<AttributeModifiable> getChangedSynchronizedAttributes:getDirtyAttributes();
    public (Collection<AttributeModifiableHandle>) Collection<AttributeModifiable> getSynchronizedAttributes:getSyncableAttributes();
#elseif version >= 1.16
    public (Set<AttributeModifiableHandle>) Set<AttributeModifiable> getChangedSynchronizedAttributes:getAttributes();
    public (Collection<AttributeModifiableHandle>) Collection<AttributeModifiable> getSynchronizedAttributes:b();
#else
    public (Set<AttributeModifiableHandle>) Set<AttributeModifiable> getChangedSynchronizedAttributes:getAttributes() {
        return ((AttributeMapServer) instance).getAttributes();
    }

    public (Collection<AttributeModifiableHandle>) Collection<AttributeModifiable> getSynchronizedAttributes() {
        return ((AttributeMapServer) instance).c();
    }
#endif

#if version >= 1.21.6
    public void loadFromNBT((CommonTagList) NBTTagList nbttaglist) {
        net.minecraft.core.HolderLookup$a holderLookup = org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry();
        RegistryOps registryops = holderLookup.createSerializationContext(DynamicOpsNBT.INSTANCE);

        java.util.List packed = (java.util.List) AttributeModifiable$a.LIST_CODEC.parse(registryops, nbttaglist)
            .resultOrPartial(NBTBaseHandle.createPartialErrorLogger(nbttaglist))
            .orElse(null);

        if (packed != null) {
            instance.apply(packed);
        }
    }
    public (CommonTagList) NBTTagList saveToNBT() {
        net.minecraft.core.HolderLookup$a holderLookup = org.bukkit.craftbukkit.CraftRegistry.getMinecraftRegistry();
        RegistryOps registryops = holderLookup.createSerializationContext(DynamicOpsNBT.INSTANCE);

        java.util.List packed = instance.pack();

        return (NBTTagList) AttributeModifiable$a.LIST_CODEC.encode(packed, registryops, new NBTTagList());
    }
#elseif version >= 1.18
    public void loadFromNBT:load((CommonTagList) NBTTagList nbttaglist);
    public (CommonTagList) NBTTagList saveToNBT:save();
#elseif version >= 1.16
    public void loadFromNBT:a((CommonTagList) NBTTagList nbttaglist);
    public (CommonTagList) NBTTagList saveToNBT:c();
#else
    public void loadFromNBT((CommonTagList) NBTTagList nbttaglist) {
        GenericAttributes.a(instance, nbttaglist);
    }
    public (CommonTagList) NBTTagList saveToNBT() {
        return GenericAttributes.a(instance);
    }
#endif
}

// Note: on very old versions it also uses IAttribute, but thats always AttributeBase anyway
class AttributeBase {
#if version >= 1.18
    public String getDescriptionId();
#else
    public String getDescriptionId:getName();
#endif
}

class GenericAttributes {
    #bootstrap com.bergerkiller.bukkit.common.internal.CommonBootstrap.initServer();

#if version >= 1.20.5
    public static final (Holder<AttributeBaseHandle>) net.minecraft.core.Holder<AttributeBase> FOLLOW_RANGE;
    public static final (Holder<AttributeBaseHandle>) net.minecraft.core.Holder<AttributeBase> MOVEMENT_SPEED;
#elseif version >= 1.16
    public static final (Holder<AttributeBaseHandle>) AttributeBase FOLLOW_RANGE;
    public static final (Holder<AttributeBaseHandle>) AttributeBase MOVEMENT_SPEED;
#elseif version >= 1.8.4
    public static final (Holder<AttributeBaseHandle>) IAttribute FOLLOW_RANGE;
    public static final (Holder<AttributeBaseHandle>) IAttribute MOVEMENT_SPEED;
#else
    public static final (Holder<AttributeBaseHandle>) IAttribute FOLLOW_RANGE:b;
    public static final (Holder<AttributeBaseHandle>) IAttribute MOVEMENT_SPEED:d;
#endif
}
