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

import com.darkmagician6.eventapi.EventTarget;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.block.entity.BarrelBlockEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.EnchantingTableBlockEntity;
import net.minecraft.block.entity.EnderChestBlockEntity;
import net.minecraft.block.entity.FurnaceBlockEntity;
import net.minecraft.block.entity.MobSpawnerBlockEntity;
import net.minecraft.block.entity.PistonBlockEntity;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.block.entity.TrappedChestBlockEntity;
import net.minecraft.client.render.Camera;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.chunk.WorldChunk;
import zenith.zov.base.events.impl.render.EventRender3D;
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.render.RenderUtils;
import zenith.zov.utility.render.level.Render3DUtil;

@ModuleAnnotation(
    name = "Storage ESP",
    category = Category.RENDER,
    description = "Renders storage blocks through walls"
)
public final class StorageESP extends Module {
    public static final StorageESP INSTANCE = new StorageESP();
    private final NumberSetting alpha = new NumberSetting("Alpha", 125.0F, 1.0F, 255.0F, 1.0F);
    private final BooleanSetting tracers = new BooleanSetting("Tracers", "Draws a line from your player to the storage block", false);
    private final BooleanSetting chests = new BooleanSetting("Chests", true);
    private final BooleanSetting enderChests = new BooleanSetting("Ender Chests", true);
    private final BooleanSetting spawners = new BooleanSetting("Spawners", true);
    private final BooleanSetting shulkerBoxes = new BooleanSetting("Shulker Boxes", true);
    private final BooleanSetting furnaces = new BooleanSetting("Furnaces", true);
    private final BooleanSetting barrels = new BooleanSetting("Barrels", true);
    private final BooleanSetting enchant = new BooleanSetting("Enchanting Tables", true);
    private final BooleanSetting pistons = new BooleanSetting("Pistons", true);

    private StorageESP() {
    }

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

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

    @EventTarget
    public void onRender3D(EventRender3D event) {
        if (mc.player != null && mc.world != null) {
            this.renderStorages(event);
        }
    }

    private Color getBlockEntityColor(BlockEntity blockEntity, int value) {
        if (blockEntity instanceof TrappedChestBlockEntity && this.chests.isEnabled()) {
            return new Color(200, 91, 0, value);
        } else if (blockEntity instanceof ChestBlockEntity && this.chests.isEnabled()) {
            return new Color(156, 91, 0, value);
        } else if (blockEntity instanceof EnderChestBlockEntity && this.enderChests.isEnabled()) {
            return new Color(117, 0, 255, value);
        } else if (blockEntity instanceof MobSpawnerBlockEntity && this.spawners.isEnabled()) {
            return new Color(138, 126, 166, value);
        } else if (blockEntity instanceof ShulkerBoxBlockEntity && this.shulkerBoxes.isEnabled()) {
            return new Color(134, 0, 158, value);
        } else if (blockEntity instanceof FurnaceBlockEntity && this.furnaces.isEnabled()) {
            return new Color(125, 125, 125, value);
        } else if (blockEntity instanceof BarrelBlockEntity && this.barrels.isEnabled()) {
            return new Color(255, 140, 140, value);
        } else if (blockEntity instanceof EnchantingTableBlockEntity && this.enchant.isEnabled()) {
            return new Color(80, 80, 255, value);
        } else {
            return blockEntity instanceof PistonBlockEntity && this.pistons.isEnabled() ? new Color(35, 226, 0, value) : new Color(255, 255, 255, 0);
        }
    }

    private void renderStorages(EventRender3D event) {
        Camera cam = mc.gameRenderer.getCamera();
        if (cam != null) {
            Vec3d camPos = RenderUtils.getCameraPos();
            MatrixStack matrices = event.getMatrix();
            matrices.push();
            matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(cam.getPitch()));
            matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(cam.getYaw() + 180.0F));
            matrices.translate(-camPos.x, -camPos.y, -camPos.z);

            for (WorldChunk chunk : this.getLoadedChunks()) {
                if (chunk != null && !chunk.isEmpty()) {
                    for (BlockPos blockPos : chunk.getBlockEntityPositions()) {
                        BlockEntity blockEntity = mc.world.getBlockEntity(blockPos);
                        if (blockEntity != null) {
                            Color color = this.getBlockEntityColor(blockEntity, (int)this.alpha.getCurrent());
                            if (color.getAlpha() != 0) {
                                Render3DUtil.drawBox(
                                    new Box(
                                        (double)blockPos.getX() + 0.1,
                                        (double)blockPos.getY() + 0.05,
                                        (double)blockPos.getZ() + 0.1,
                                        (double)blockPos.getX() + 0.9,
                                        (double)blockPos.getY() + 0.85,
                                        (double)blockPos.getZ() + 0.9
                                    ),
                                    color.getRGB(),
                                    1.0F,
                                    true,
                                    true,
                                    false
                                );
                                if (this.tracers.isEnabled() && mc.crosshairTarget != null) {
                                    Vec3d start = mc.crosshairTarget.getPos();
                                    Vec3d end = new Vec3d(
                                        (double)blockPos.getX() + 0.5, (double)blockPos.getY() + 0.5, (double)blockPos.getZ() + 0.5
                                    );
                                    Render3DUtil.drawLine(start, end, color.getRGB(), 1.0F, false);
                                }
                            }
                        }
                    }
                }
            }

            matrices.pop();
        }
    }

    private List<WorldChunk> getLoadedChunks() {
        List<WorldChunk> chunks = new ArrayList<>();
        int viewDist = (Integer)mc.options.getViewDistance().getValue();

        for (int x = -viewDist; x <= viewDist; x++) {
            for (int z = -viewDist; z <= viewDist; z++) {
                WorldChunk chunk = mc.world
                    .getChunkManager()
                    .getWorldChunk((int)mc.player.getX() / 16 + x, (int)mc.player.getZ() / 16 + z);
                if (chunk != null) {
                    chunks.add(chunk);
                }
            }
        }

        return chunks;
    }
}
