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

import net.minecraft.resources.RegistryOps;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.ListTag;

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

import com.bergerkiller.generated.net.minecraft.nbt.TagHandle;
import com.bergerkiller.generated.net.minecraft.world.entity.ai.attributes.AttributeHandle;
import com.bergerkiller.generated.net.minecraft.world.entity.ai.attributes.AttributeMapHandle;
import com.bergerkiller.generated.net.minecraft.world.entity.ai.attributes.AttributeInstanceHandle;

class AttributeInstance {
#if version >= 1.20.5
    public (Holder<AttributeHandle>) net.minecraft.core.Holder<Attribute> getAttribute();
#elseif version >= 1.16
    public (Holder<AttributeHandle>) Attribute getAttribute();
#else
    public (Holder<AttributeHandle>) 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 AttributeMap {
#if version >= 1.16
    public (Collection<AttributeInstanceHandle>) Collection<AttributeInstance> getAllAttributes() {
  #if version >= 1.20.5
        #require AttributeMap private final java.util.Map<net.minecraft.core.Holder<Attribute>, AttributeInstance> attributesMap:attributes;
  #elseif version >= 1.17
        #require AttributeMap private final java.util.Map<Attribute, AttributeInstance> attributesMap:attributes;
  #else
        #require AttributeMap private final java.util.Map<Attribute, AttributeInstance> attributesMap:b;
  #endif
        java.util.Map attributes = instance#attributesMap;
        return attributes.values();
    }
#else
    public (Collection<AttributeInstanceHandle>) Collection<AttributeInstance> getAllAttributes() {
        return instance.a();
    }
#endif

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

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

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

        java.util.List packed = (java.util.List) AttributeInstance$Packed.LIST_CODEC.parse(registryops, nbttaglist)
            .resultOrPartial(TagHandle.createPartialErrorLogger(nbttaglist))
            .orElse(null);

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

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

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

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

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

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