package net.minecraft.world.effect;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.effect.MobEffect;

import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;

import com.bergerkiller.generated.net.minecraft.nbt.CompoundTagHandle;
import com.bergerkiller.generated.net.minecraft.world.effect.MobEffectInstanceHandle;
import com.bergerkiller.generated.net.minecraft.world.effect.MobEffectHandle;
import com.bergerkiller.bukkit.common.nbt.CommonTagCompound;
import com.bergerkiller.bukkit.common.wrappers.Holder;

class MobEffectInstance {
#if version >= 1.20.5
    private final (Holder<MobEffectHandle>) net.minecraft.core.Holder<MobEffect> effectList:effect;
#elseif version >= 1.17
    private final (Holder<MobEffectHandle>) MobEffect effectList:effect;
#elseif version >= 1.9
    private final (Holder<MobEffectHandle>) MobEffect effectList:b;
#else
    private (Holder<MobEffectHandle>) int effectList:effectId;
#endif

#if version >= 1.17
    private int duration;
    private int amplifier;
    private boolean ambient;
#else
    private int duration;
    private int amplifier:amplification;
    private boolean ambient;
#endif

#if version >= 1.17
    private boolean particles:visible;
#elseif version >= 1.15.2
    private boolean particles:showParticles;
#elseif version >= 1.9
    private boolean particles:h;
#else
    private boolean particles:particles;
#endif

    //TODO: showIcon?
    //TODO: hiddenEffect?

#if version >= 1.21.5
    public static (MobEffectInstanceHandle) MobEffectInstance fromNBT((CommonTagCompound) CompoundTag compound) {
        //TODO: Should this use this whole mess or not?
        // RegistryOps<NBTBase> registryops = this.registryAccess().<NBTBase>createSerializationContext(NbtOps.INSTANCE);
        com.mojang.serialization.DynamicOps dynamicops = net.minecraft.nbt.NbtOps.INSTANCE;
        return (MobEffectInstance) MobEffectInstance.CODEC.parse(dynamicops, compound)
            .resultOrPartial(CompoundTagHandle.createPartialErrorLogger(compound))
            .orElse(null);
    }
#elseif version >= 1.18
    public static (MobEffectInstanceHandle) MobEffectInstance fromNBT:load((CommonTagCompound) CompoundTag compound);
#else
    public static (MobEffectInstanceHandle) MobEffectInstance fromNBT:b((CommonTagCompound) CompoundTag compound);
#endif

    public PotionEffect toBukkit() {
#if version >= 1.9 || exists org.bukkit.craftbukkit.potion.CraftPotionUtil public static org.bukkit.potion.PotionEffect toBukkit(net.minecraft.world.effect.MobEffectInstance effect);
        return CraftPotionUtil.toBukkit(instance);
#else
        // Fallback for before this method was added
  #if exists net.minecraft.world.effect.MobEffectInstance public int getEffectId();
        PotionEffectType type = PotionEffectType.getById(instance.getEffectId());
  #else
        MobEffectInstanceHandle mobEffectHandle = MobEffectInstanceHandle.createHandle(instance); // Weird!
        MobEffectHandle mobEffectType = mobEffectHandle.getEffectList();
        int mobEffectTypeId = MobEffectHandle.getId(mobEffectType);
        PotionEffectType type = PotionEffectType.getById(mobEffectTypeId);
  #endif
        int amp = instance.getAmplifier();
        int duration = instance.getDuration();
        boolean ambient = instance.isAmbient();
        boolean particles = instance.isShowParticles();
        return new PotionEffect(type, duration, amp, ambient, particles);
#endif
    }

    public static (MobEffectInstanceHandle) MobEffectInstance fromBukkit(PotionEffect effect) {
#if version >= 1.9 || exists org.bukkit.craftbukkit.potion.CraftPotionUtil public static net.minecraft.world.effect.MobEffectInstance fromBukkit(org.bukkit.potion.PotionEffect effect);
        return CraftPotionUtil.fromBukkit(effect);
#elseif exists net.minecraft.world.effect.MobEffectInstance public MobEffectInstance(int effectId, int duration, int amplification, boolean ambient, boolean particles);
        // Fallback for before this method was added
        int effectId = effect.getType().getId();
        return new MobEffectInstance(effectId, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles());
#else
        // Fallback for before this method was added (weird edge case)
        MobEffectInstanceList type = MobEffectInstanceListHandle.fromId(effect.getType().getId()).getRaw();
        return new MobEffectInstance(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles());
#endif
    }
}

class MobEffect {
#if version >= 1.20.5
    public org.bukkit.potion.PotionEffectType toBukkit() {
        return org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftToBukkit(instance);
    }

    public static (MobEffectHandle) MobEffect fromBukkit(org.bukkit.potion.PotionEffectType effectType) {
        return (MobEffect) org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraft(effectType);
    }

    public static (Holder<MobEffectHandle>) net.minecraft.core.Holder<MobEffect> holderFromBukkit(org.bukkit.potion.PotionEffectType effectType) {
        return org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(effectType);
    }

    public static org.bukkit.potion.PotionEffectType holderToBukkit((Holder<MobEffectHandle>) net.minecraft.core.Holder<MobEffect> mobEffectList) {
        return org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftHolderToBukkit(mobEffectList);
    }
#else
    public org.bukkit.potion.PotionEffectType toBukkit() {
        com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod getIdRaw;
        getIdRaw = (com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod) MobEffectHandle.T.getId.raw;
        return org.bukkit.potion.PotionEffectType.getById(((Integer) getIdRaw.invoke(instance)).intValue());
    }

    public static (MobEffectHandle) MobEffect fromBukkit(org.bukkit.potion.PotionEffectType effectType) {
        com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod fromIdRaw;
        fromIdRaw = (com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod) MobEffectHandle.T.fromId.raw;
        return (MobEffect) fromIdRaw.invoke(Integer.valueOf(effectType.getId()));
    }

    public static (Holder<MobEffectHandle>) MobEffect holderFromBukkit(org.bukkit.potion.PotionEffectType effectType) {
        com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod fromIdRaw;
        fromIdRaw = (com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod) MobEffectHandle.T.fromId.raw;
        return (MobEffect) fromIdRaw.invoke(Integer.valueOf(effectType.getId()));
    }

    public static org.bukkit.potion.PotionEffectType holderToBukkit((Holder<MobEffectHandle>) MobEffect mobEffectList) {
        com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod getIdRaw;
        getIdRaw = (com.bergerkiller.mountiplex.reflection.declarations.Template$StaticMethod) MobEffectHandle.T.getId.raw;
        return org.bukkit.potion.PotionEffectType.getById(((Integer) getIdRaw.invoke(mobEffectList)).intValue());
    }
#endif

#if exists MobEffect public static int getId(MobEffect mobeffectlist);
    public static int getId((MobEffectHandle) MobEffect mobeffectlist);
#elseif version >= 1.18
    public static int getId((MobEffectHandle) MobEffect mobeffectlist) {
        return net.minecraft.core.registries.BuiltInRegistries.MOB_EFFECT.getId((Object) mobeffectlist);
    }
#elseif version < 1.9 && exists net.minecraft.world.effect.MobEffect public final int id;
    public static int getId((MobEffectHandle) MobEffect mobeffectlist) {
        return mobeffectlist.id;
    }
#else
    public static int getId((MobEffectHandle) MobEffect mobeffectlist);
#endif

#if exists MobEffect public static MobEffect byId(int id);
    public static (MobEffectHandle) MobEffect fromId:byId(int id);
#elseif version >= 1.18
    public static (MobEffectHandle) MobEffect fromId(int id) {
        return (MobEffect) net.minecraft.core.registries.BuiltInRegistries.MOB_EFFECT.byId(id);
    }
#elseif version < 1.9 && exists net.minecraft.world.effect.MobEffect public static final MobEffect[] byId;
    // NachoSpigot 1.8.8 has some weird hack thing
    public static (MobEffectHandle) MobEffect fromId(int id) {
        MobEffect[] byId = MobEffect.byId;
        return (id >= 0 && id < byId.length) ? byId[id] : null;
    }
#else
    public static (MobEffectHandle) MobEffect fromId(int id);
#endif
}
