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

import com.darkmagician6.eventapi.EventManager;
import com.darkmagician6.eventapi.EventTarget;
import net.minecraft.item.Items;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.hit.HitResult.Type;
import net.minecraft.util.math.BlockPos;
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;

@ModuleAnnotation(
    name = "WindHop",
    description = "Use wind charges to boost yourself up by throwing them at the ground",
    category = Category.MOVEMENT
)
public class WindHop extends Module {
    private final BooleanSetting autoLookDown = new BooleanSetting("Auto Look Down", true);
    private final BooleanSetting autoThrow = new BooleanSetting("Auto Throw", true);
    private final NumberSetting lookDownAngle = new NumberSetting("Look Down Angle", 80.0F, 0.0F, 90.0F, 1.0F);
    private final BooleanSetting silent = new BooleanSetting("Silent", false);
    private final BooleanSetting noRotate = new BooleanSetting("No Rotate", false);
    private boolean isActivated = false;
    private int windChargeSlot = -1;
    private int originalSlot = -1;

    public WindHop() {
        EventManager.register(this);
    }

    @EventTarget
    public void onUpdate(EventUpdate event) {
        if (mc.player != null && mc.world != null) {
            if (this.isEnabled()) {
                if (!this.isActivated) {
                    this.activateWindHop();
                }

                this.handleWindHop();
            } else {
                if (this.isActivated && this.silent.isEnabled() && this.originalSlot != -1) {
                    mc.player.getInventory().setSelectedSlot(this.originalSlot);
                }

                this.isActivated = false;
            }
        }
    }

    private void activateWindHop() {
        this.windChargeSlot = this.findWindChargeSlot();
        if (this.windChargeSlot != -1) {
            this.isActivated = true;
            if (this.silent.isEnabled()) {
                this.originalSlot = mc.player.getInventory().selectedSlot;
            } else {
                mc.player.getInventory().setSelectedSlot(this.windChargeSlot);
            }
        }
    }

    private void handleWindHop() {
        if (this.autoLookDown.isEnabled() && !this.noRotate.isEnabled()) {
            mc.player.setPitch(this.lookDownAngle.getCurrent());
        }

        if (this.autoThrow.isEnabled()) {
            this.throwWindChargeAtGround();
        }
    }

    private void throwWindChargeAtGround() {
        BlockPos targetBlock;
        if (this.noRotate.isEnabled()) {
            BlockPos playerPos = mc.player.getBlockPos();
            targetBlock = this.findGroundBelow(playerPos);
        } else {
            HitResult hitResult = mc.player.raycast(10.0, 0.0F, true);
            if (hitResult.getType() != Type.BLOCK) {
                return;
            }

            targetBlock = ((BlockHitResult)hitResult).getBlockPos();
        }

        if (targetBlock != null) {
            if (this.silent.isEnabled()) {
                mc.player.getInventory().setSelectedSlot(this.windChargeSlot);
            }

            mc.interactionManager.interactItem(mc.player, Hand.MAIN_HAND);
            if (!this.silent.isEnabled()) {
                mc.player.swingHand(Hand.MAIN_HAND);
            }

            if (this.silent.isEnabled() && this.originalSlot != -1) {
                mc.player.getInventory().setSelectedSlot(this.originalSlot);
            }
        }
    }

    private BlockPos findGroundBelow(BlockPos startPos) {
        for (int y = startPos.getY() - 1; y >= startPos.getY() - 10; y--) {
            BlockPos checkPos = new BlockPos(startPos.getX(), y, startPos.getZ());
            if (!mc.world.getBlockState(checkPos).isAir()) {
                return checkPos;
            }
        }

        return null;
    }

    private int findWindChargeSlot() {
        for (int i = 0; i < 9; i++) {
            if (!mc.player.getInventory().getStack(i).isEmpty() && mc.player.getInventory().getStack(i).getItem() == Items.WIND_CHARGE) {
                return i;
            }
        }

        return -1;
    }
}
