package com.shanebeestudios.skbee.api.particle;

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import com.shanebeestudios.skbee.api.util.Util;
import com.shanebeestudios.skbee.api.util.legacy.LegacyUtils;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Particle.DustOptions;
import org.bukkit.Particle.DustTransition;
import org.bukkit.Vibration;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * Utility class for {@link Particle particles}
 */
public class ParticleUtil {

    private ParticleUtil() {
    }

    private static final boolean HAS_GEYSER = LegacyUtils.IS_RUNNING_MC_26_2;
    private static final boolean HAS_PLAYER_FORCE = Skript.methodExists(Player.class, "spawnParticle",
        Particle.class, Location.class, int.class, double.class, double.class, double.class, double.class, Object.class, boolean.class);

    public static void spawnParticle(@NotNull Particle particle, @Nullable Player[] players, @NotNull Location location, int count, Object data, Vector offset, double extra, boolean force) {
        Object particleData = getData(particle, data);
        if (particle.getDataType() != Void.class && particleData == null) return;

        double x = offset.getX();
        double y = offset.getY();
        double z = offset.getZ();
        if (players == null) {
            World world = location.getWorld();
            if (world == null) return;
            world.spawnParticle(particle, location, count, x, y, z, extra, particleData, force);
        } else {
            for (Player player : players) {
                assert player != null;
                if (HAS_PLAYER_FORCE) {
                    player.spawnParticle(particle, location, count, x, y, z, extra, particleData, force);
                } else {
                    player.spawnParticle(particle, location, count, x, y, z, extra, particleData);
                }
            }
        }
    }

    public static String getDataType(Particle particle) {
        Class<?> dataType = particle.getDataType();
        if (dataType == ItemStack.class) {
            return "itemtype";
        } else if (dataType == Particle.DustOptions.class) {
            return "dust-option";
        } else if (dataType == BlockData.class) {
            return "blockdata/itemtype";
        } else if (dataType == Particle.DustTransition.class) {
            return "dust-transition";
        } else if (dataType == Vibration.class) {
            return "vibration";
        } else if (dataType == Integer.class) {
            return "number(int)";
        } else if (dataType == Float.class) {
            return "number(float)";
        } else if (dataType == Color.class) {
            return "color/bukkitcolor";
        } else if (dataType == Particle.Trail.class) {
            return "trail";
        } else if (dataType == Particle.Spell.class) {
            return "spell";
        } else if (HAS_GEYSER && dataType == Particle.GeyserBase.class) {
            return "geyserbase";
        } else if (HAS_GEYSER && dataType == Particle.Geyser.class) {
            return "geyser";
        }
        // For future particle data additions that haven't been added here yet
        Util.debug("Missing particle data type: '&e" + dataType.getName() + "&7'");
        return "UNKNOWN";
    }

    @Nullable
    public static Object getData(Particle particle, Object data) {
        Class<?> dataType = particle.getDataType();
        if (dataType == Void.class) {
            return null;
        } else if (dataType == Float.class && data instanceof Number number) {
            return number.floatValue();
        } else if (dataType == Integer.class && data instanceof Number number) {
            return number.intValue();
        } else if (dataType == ItemStack.class && data instanceof ItemType itemType) {
            return itemType.getRandom();
        } else if (dataType == DustOptions.class && data instanceof DustOptions) {
            return data;
        } else if (dataType == DustTransition.class && data instanceof DustTransition) {
            return data;
        } else if (dataType == Vibration.class && data instanceof Vibration) {
            return data;
        } else if (dataType == Color.class && data instanceof ch.njol.skript.util.Color skriptColor) {
            return skriptColor.asBukkitColor();
        } else if (dataType == Color.class && data instanceof Color) {
            return data;
        } else if (dataType == BlockData.class) {
            if (data instanceof BlockData) {
                return data;
            } else if (data instanceof ItemType itemType) {
                Material material = itemType.getMaterial();
                if (material.isBlock()) {
                    return material.createBlockData();
                }
            }
        } else if (dataType == Particle.Trail.class && data instanceof Particle.Trail) {
            return data;
        } else if (dataType == Particle.Spell.class && data instanceof Particle.Spell) {
            return data;
        } else if (HAS_GEYSER && dataType == Particle.GeyserBase.class && data instanceof Particle.GeyserBase) {
            return data;
        } else if (HAS_GEYSER && dataType == Particle.Geyser.class && data instanceof Particle.Geyser) {
            return data;
        }
        return null;
    }

}
