package zenith.zov.client.modules.impl.crystal;

import com.darkmagician6.eventapi.EventTarget;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.block.Blocks;
import net.minecraft.block.RespawnAnchorBlock;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.item.ShieldItem;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult.Type;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import org.lwjgl.glfw.GLFW;
import zenith.zov.base.events.impl.player.EventUpdate;
import zenith.zov.client.modules.api.Category;
import zenith.zov.client.modules.api.Module;
import zenith.zov.client.modules.api.ModuleAnnotation;
import zenith.zov.client.modules.api.setting.impl.BooleanSetting;
import zenith.zov.client.modules.api.setting.impl.NumberSetting;
import zenith.zov.utility.interfaces.IMinecraft;

@ModuleAnnotation(
    name = "AnchorMacro",
    category = Category.CRYSTAL,
    description = "Automatically blows up respawn anchors for you"
)
public final class AnchorMacro extends Module implements IMinecraft {
    public static final AnchorMacro INSTANCE = new AnchorMacro();
    private final BooleanSetting whileUse = new BooleanSetting("While Use", true);
    private final BooleanSetting stopOnKill = new BooleanSetting("Stop on Kill", false);
    private final BooleanSetting clickSimulation = new BooleanSetting("Click Simulation", false);
    private final NumberSetting switchDelay = new NumberSetting("Switch Delay", 0.0F, 0.0F, 20.0F, 1.0F);
    private final NumberSetting glowstoneDelay = new NumberSetting("Glowstone Delay", 0.0F, 0.0F, 20.0F, 1.0F);
    private final NumberSetting explodeDelay = new NumberSetting("Explode Delay", 0.0F, 0.0F, 20.0F, 1.0F);
    private final NumberSetting explodeSlot = new NumberSetting("Explode Slot", 1.0F, 1.0F, 9.0F, 1.0F);
    private final BooleanSetting onlyCharge = new BooleanSetting("Only Charge", false);
    private int switchClock = 0;
    private int glowstoneClock = 0;
    private int explodeClock = 0;
    private final Set<BlockPos> ownedAnchors = new HashSet<>();

    private AnchorMacro() {
    }

    @Override
    public void onEnable() {
        this.switchClock = 0;
        this.glowstoneClock = 0;
        this.explodeClock = 0;
        super.onEnable();
    }

    @Override
    public void onDisable() {
        super.onDisable();
    }

    @EventTarget
    public void onUpdate(EventUpdate event) {
        if (mc.currentScreen == null) {
            if (this.whileUse.isEnabled() || !this.isUsingItem()) {
                if (!this.stopOnKill.isEnabled() || !this.isDeadBodyNearby()) {
                    if (GLFW.glfwGetMouseButton(mc.getWindow().getHandle(), 1) == 1
                        && mc.crosshairTarget instanceof BlockHitResult hit
                        && this.isRespawnAnchor(hit.getBlockPos())) {
                        mc.options.useKey.setPressed(false);
                        if (this.isAnchorNotCharged(hit.getBlockPos())) {
                            this.handleGlowstonePlacement(hit);
                        }

                        if (this.isAnchorCharged(hit.getBlockPos())) {
                            this.handleAnchorExplosion(hit);
                        }
                    }
                }
            }
        }
    }

    private boolean isUsingItem() {
        return mc.player.getMainHandStack().getItem().getComponents().contains(DataComponentTypes.FOOD)
            || mc.player.getMainHandStack().getItem() instanceof ShieldItem
            || mc.player.getOffHandStack().getItem() instanceof ShieldItem
            || mc.player.getOffHandStack().getItem().getComponents().contains(DataComponentTypes.FOOD);
    }

    private boolean isDeadBodyNearby() {
        return false;
    }

    private boolean isRespawnAnchor(BlockPos pos) {
        return mc.world.getBlockState(pos).getBlock() == Blocks.RESPAWN_ANCHOR;
    }

    private boolean isAnchorNotCharged(BlockPos pos) {
        return (Integer)mc.world.getBlockState(pos).get(RespawnAnchorBlock.CHARGES) == 0;
    }

    private boolean isAnchorCharged(BlockPos pos) {
        return (Integer)mc.world.getBlockState(pos).get(RespawnAnchorBlock.CHARGES) > 0;
    }

    private void handleGlowstonePlacement(BlockHitResult hit) {
        if (!mc.player.getMainHandStack().isOf(Items.GLOWSTONE)) {
            if ((float)this.switchClock < this.switchDelay.getCurrent()) {
                this.switchClock++;
                return;
            }

            this.switchClock = 0;
            this.selectItemFromHotbar(Items.GLOWSTONE);
        }

        if (mc.player.getMainHandStack().isOf(Items.GLOWSTONE)) {
            if ((float)this.glowstoneClock < this.glowstoneDelay.getCurrent()) {
                this.glowstoneClock++;
                return;
            }

            this.glowstoneClock = 0;
            if (this.clickSimulation.isEnabled()) {
            }

            this.placeBlock(hit);
        }
    }

    private void handleAnchorExplosion(BlockHitResult hit) {
        int slot = (int)this.explodeSlot.getCurrent() - 1;
        if (mc.player.getInventory().selectedSlot != slot) {
            if ((float)this.switchClock < this.switchDelay.getCurrent()) {
                this.switchClock++;
                return;
            }

            this.switchClock = 0;
            mc.player.getInventory().selectedSlot = slot;
        }

        if (mc.player.getInventory().selectedSlot == slot) {
            if ((float)this.explodeClock < this.explodeDelay.getCurrent()) {
                this.explodeClock++;
                return;
            }

            this.explodeClock = 0;
            if (!this.onlyCharge.isEnabled()) {
                if (this.clickSimulation.isEnabled()) {
                }

                this.placeBlock(hit);
                this.ownedAnchors.remove(hit.getBlockPos());
            }
        }
    }

    private void selectItemFromHotbar(Item item) {
        for (int i = 0; i < 9; i++) {
            if (mc.player.getInventory().getStack(i).isOf(item)) {
                mc.player.getInventory().selectedSlot = i;
                break;
            }
        }
    }

    private void placeBlock(BlockHitResult hit) {
        if (mc.interactionManager != null) {
            mc.interactionManager.interactBlock(mc.player, mc.player.getActiveHand(), hit);
        }
    }

    @EventTarget
    public void onItemUse(EventUpdate event) {
        if (mc.crosshairTarget instanceof BlockHitResult hitResult && hitResult.getType() == Type.BLOCK) {
            if (mc.player.getMainHandStack().isOf(Items.RESPAWN_ANCHOR)) {
                Direction dir = hitResult.getSide();
                BlockPos pos = hitResult.getBlockPos();
                if (!mc.world.getBlockState(pos).isReplaceable()) {
                    switch (dir) {
                        case UP:
                            this.ownedAnchors.add(pos.add(0, 1, 0));
                            break;
                        case DOWN:
                            this.ownedAnchors.add(pos.add(0, -1, 0));
                            break;
                        case EAST:
                            this.ownedAnchors.add(pos.add(1, 0, 0));
                            break;
                        case WEST:
                            this.ownedAnchors.add(pos.add(-1, 0, 0));
                            break;
                        case NORTH:
                            this.ownedAnchors.add(pos.add(0, 0, -1));
                            break;
                        case SOUTH:
                            this.ownedAnchors.add(pos.add(0, 0, 1));
                    }
                } else {
                    this.ownedAnchors.add(pos);
                }
            }

            BlockPos bp = hitResult.getBlockPos();
            if (this.isAnchorCharged(bp)) {
                this.ownedAnchors.remove(bp);
            }
        }
    }
}
