/FileExtraction/Java_unseen/ionar2_summit/src/main/java/com/salhack/summit/module/world/EnderChestFarmer.java
package com.salhack.summit.module.world;

import com.salhack.summit.managers.BlockManager;
import com.salhack.summit.SummitMod;
import com.salhack.summit.events.MinecraftEvent.Stage;
import com.salhack.summit.events.bus.EventHandler;
import com.salhack.summit.events.bus.Listener;
import com.salhack.summit.events.player.EventPlayerDamageBlock;
import com.salhack.summit.events.player.EventPlayerMotionUpdate;
import com.salhack.summit.events.player.EventPlayerUpdate;
import com.salhack.summit.module.Module;
import com.salhack.summit.module.Value;
import com.salhack.summit.util.BlockInteractionHelper;
import com.salhack.summit.util.BlockInteractionHelper.PlaceResult;
import com.salhack.summit.util.Timer;
import com.salhack.summit.util.entity.EntityUtil;
import com.salhack.summit.util.entity.PlayerUtil;
import net.minecraft.block.BlockEnderChest;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.network.play.client.CPacketPlayerDigging;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;

import java.util.Comparator;

public class EnderChestFarmer extends Module
{
    public static Value<String> Mode = new Value<>("Mode", new String[]{"M"}, "Mode to use for mining", "Packet");
    public static Value<Integer> Radius = new Value<Integer>("Radius", new String[]{"R"}, "Radius to search for enderchests, and place them", 4, 0, 10, 1);
    public Value<Float> Delay = new Value<Float>("Delay", new String[]{"D"}, "Timed delay for each place of ender chest", 1f, 0f, 10f, 1f);

    public EnderChestFarmer()
    {
        super("ObsidianMaker", new String[]{"EChestFarmer"}, "Automatically places enderchests around you, and attempts to mine it", "NONE", -1, ModuleType.WORLD);
        setMetaData(getMetaData());
        
        Mode.addString("Packet");
        Mode.addString("Normal");
        Mode.addString("PvP");
    }

    private Timer PlaceTimer = new Timer();

    public String getMetaData()
    {
        return String.valueOf(Mode.getValue());
    }

    @EventHandler
    private Listener<EventPlayerUpdate> onPlayerUpdate = new Listener<>(event ->
    {
        setMetaData(getMetaData());
    });

    @EventHandler
    private Listener<EventPlayerMotionUpdate> OnPlayerUpdate = new Listener<>(p_Event ->
    {
        if (p_Event.getStage() != Stage.Pre || p_Event.isCancelled()) return;
        if (Mode.getValue().equals("Normal") || Mode.getValue().equals("PvP"))
        {
            if (BlockManager.Update(Radius.getValue(), true))
            {
                p_Event.cancel();

                final double l_Pos[] = EntityUtil.calculateLookAt(BlockManager.GetCurrBlock().getX() + 0.5, BlockManager.GetCurrBlock().getY() - 0.5, BlockManager.GetCurrBlock().getZ() + 0.5, mc.player);

                p_Event.setPitch(l_Pos[1]);
                p_Event.setYaw(l_Pos[0]);

                return;
            }
        }

        BlockPos l_ClosestPos = BlockInteractionHelper.getSphere(PlayerUtil.GetLocalPlayerPosFloored(), Radius.getValue(), Radius.getValue(), false, true, 0).stream().filter(p_Pos -> IsValidBlockPos(p_Pos)).min(Comparator.comparing(p_Pos -> EntityUtil.GetDistanceOfEntityToBlock(mc.player, p_Pos))).orElse(null);

        if (l_ClosestPos != null)
        {
            boolean hasPickaxe = mc.player.getHeldItemMainhand().getItem() == Items.DIAMOND_PICKAXE;

            if (!hasPickaxe)
            {
                for (int i = 0; i < 9; ++i)
                {
                    ItemStack stack = mc.player.inventory.getStackInSlot(i);

                    if (stack.isEmpty()) continue;

                    if (stack.getItem() == Items.DIAMOND_PICKAXE)
                    {
                        hasPickaxe = true;
                        mc.player.inventory.currentItem = i;
                        mc.playerController.updateController();
                        break;
                    }
                }
            }
            if (!hasPickaxe) return;

            if (Mode.getValue().equals("Packet"))
            {
                p_Event.cancel();

                final double l_Pos[] = EntityUtil.calculateLookAt(l_ClosestPos.getX() + 0.5, l_ClosestPos.getY() - 0.5, l_ClosestPos.getZ() + 0.5, mc.player);

                p_Event.setPitch(l_Pos[1]);
                p_Event.setYaw(l_Pos[0]);

                mc.player.swingArm(EnumHand.MAIN_HAND);
                mc.player.connection.sendPacket(new CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, l_ClosestPos, EnumFacing.UP));
                mc.player.connection.sendPacket(new CPacketPlayerDigging(CPacketPlayerDigging.Action.STOP_DESTROY_BLOCK, l_ClosestPos, EnumFacing.UP));
                SummitMod.EVENT_BUS.post(new EventPlayerDamageBlock(l_ClosestPos, EnumFacing.UP));
            } else BlockManager.SetCurrentBlock(l_ClosestPos);

        }

        else
        {
            if (!Mode.getValue().equals("PvP"))
            {
                if (!PlaceTimer.passed(Delay.getValue() * 1000)) return;

                PlaceTimer.reset();

                if (!IsCurrItemEnderChest())
                {
                    int slot = GetEnderChestSlot();

                    if (slot == -1) return;

                    mc.player.inventory.currentItem = slot;
                    mc.playerController.updateController();
                }

                for (BlockPos pos : BlockInteractionHelper.getSphere(PlayerUtil.GetLocalPlayerPosFloored(), Radius.getValue(), Radius.getValue(), false, true, 0))
                {
                    PlaceResult result = BlockInteractionHelper.place(pos, Radius.getValue(), true, false);

                    if (result == PlaceResult.Placed)
                    {
                        p_Event.cancel();

                        final double rotations[] = EntityUtil.calculateLookAt(pos.getX() + 0.5, pos.getY() - 0.5, pos.getZ() + 0.5, mc.player);

                        p_Event.setPitch(rotations[1]);
                        p_Event.setYaw(rotations[0]);
                        return;
                    }
                }
            }

            // Jumpinqq's shitty pvp mode... lol
            // Instead of placing at the set range it places where you are aiming
            else if (Mode.getValue().equals("PvP"))
            {
                if (!IsCurrItemEnderChest())
                {
                    int slot = GetEnderChestSlot();

                    if (slot == -1) return;

                    mc.player.inventory.currentItem = slot;
                    mc.playerController.updateController();
                }

                if (IsCurrItemEnderChest())
                {
                    KeyBinding.onTick(Minecraft.getMinecraft().gameSettings.keyBindUseItem.getKeyCode());
                }
            }
        }
    });


    private boolean IsValidBlockPos(final BlockPos p_Pos)
    {
        IBlockState l_State = mc.world.getBlockState(p_Pos);

        if (l_State.getBlock() instanceof BlockEnderChest) return true;

        return false;
    }

    private boolean IsCurrItemEnderChest()
    {
        if (mc.player.getHeldItemMainhand().getItem() instanceof ItemBlock)
        {
            final ItemBlock block = (ItemBlock) mc.player.getHeldItemMainhand().getItem();
            return block.getBlock() == Blocks.ENDER_CHEST;
        }

        return false;
    }

    private int GetEnderChestSlot()
    {
        for (int i = 0; i < 9; ++i)
        {
            ItemStack stack = mc.player.inventory.getStackInSlot(i);

            if (stack.isEmpty() || !(stack.getItem() instanceof ItemBlock)) continue;

            final ItemBlock block = (ItemBlock) stack.getItem();
            if (block.getBlock() == Blocks.ENDER_CHEST) return i;
        }

        return -1;
    }
}
