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

import com.darkmagician6.eventapi.EventTarget;
import com.mojang.blaze3d.systems.RenderSystem;
import java.util.ArrayList;
import java.util.Arrays;
import net.minecraft.client.render.DiffuseLighting;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.text.MutableText;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import org.joml.Vector4d;
import zenith.zov.Zenith;
import zenith.zov.base.events.impl.render.EventRender2D;
import zenith.zov.base.events.impl.render.EventRender3D;
import zenith.zov.base.font.Font;
import zenith.zov.base.font.Fonts;
import zenith.zov.base.theme.Theme;
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.ModeSetting;
import zenith.zov.client.modules.api.setting.impl.MultiBooleanSetting;
import zenith.zov.client.modules.api.setting.impl.NumberSetting;
import zenith.zov.client.modules.impl.misc.NameProtect;
import zenith.zov.utility.game.other.TextUtil;
import zenith.zov.utility.game.player.PlayerIntersectionUtil;
import zenith.zov.utility.math.MathUtil;
import zenith.zov.utility.math.ProjectionUtil;
import zenith.zov.utility.render.display.Render2DUtil;
import zenith.zov.utility.render.display.base.BorderRadius;
import zenith.zov.utility.render.display.base.CustomDrawContext;
import zenith.zov.utility.render.display.base.color.ColorRGBA;
import zenith.zov.utility.render.display.shader.DrawUtil;
import zenith.zov.utility.render.level.Render3DUtil;

@ModuleAnnotation(
    name = "EntityESP",
    category = Category.RENDER,
    description = "ESP"
)
public final class EntityESP extends Module {
    public static final EntityESP INSTANCE = new EntityESP();
    private final MultiBooleanSetting elements = MultiBooleanSetting.create("Elements", Arrays.asList("Names", "Items", "Armor", "Triangles", "Boxes", "Hands"));
    private final ModeSetting textMode = new ModeSetting("Font");
    private final ModeSetting.Value mojo = new ModeSetting.Value(this.textMode, "Minecraft");
    private final ModeSetting.Value zenith = new ModeSetting.Value(this.textMode, "Zenith").select();
    private final NumberSetting scale = new NumberSetting("Size", 1.0F, 0.5F, 2.0F, 0.1F);
    private final BooleanSetting blur = new BooleanSetting("Blur", "Requires good PC", false, Interface.INSTANCE::isBlur);
    private final BooleanSetting glow = new BooleanSetting("Glow", "Needs powerful PC", false, Interface.INSTANCE::isGlow);

    private EntityESP() {
    }

    public boolean isRenderName() {
        return this.isEnabled() && this.elements.isEnable(0);
    }

    private boolean isElementEnabled(String elementName) {
        return this.elements.isEnable(elementName);
    }

    @EventTarget
    public void onHudRender(EventRender3D event) {
        if (this.elements.isEnable(4)) {
            for (Entity ent : mc.world.getPlayers()) {
                if (ent instanceof PlayerEntity) {
                    PlayerEntity entity = (PlayerEntity)ent;
                    if (entity != mc.player || !mc.options.getPerspective().isFirstPerson()) {
                        Render3DUtil.drawBox(
                            entity.getBoundingBox().offset(MathUtil.interpolate(entity).subtract(entity.getPos())),
                            Zenith.getInstance().getThemeManager().getClientColor(180).getRGB(),
                            1.0F
                        );
                    }
                }
            }
        }
    }

    @EventTarget
    public void onHudRender(EventRender2D event) {
        Render2DUtil.onRender(event.getContext());
        if (mc.player != null && mc.world != null && mc.getEntityRenderDispatcher().camera != null) {
            try {
                RenderSystem.depthMask(false);
                CustomDrawContext context = event.getContext();

                for (Entity ent : mc.world.getEntities()) {
                    if (ent instanceof PlayerEntity entity) {
                        if (this.elements.isEnable(5) && this.elements.isEnable(5)) {
                            Vector4d vec4d = ProjectionUtil.getVector4D(entity);
                            this.drawHands(event.getContext(), entity, vec4d);
                        }

                        if (this.elements.isEnable(0)) {
                            this.renderNameTag(context, entity, event.getTickDelta());
                        }

                        if (this.elements.isEnable(3)) {
                            this.renderEntityBox(context, entity, event.getTickDelta());
                        }
                    }

                    if (ent instanceof ItemEntity entity && this.elements.isEnable(1)) {
                        this.renderItemESP(context, entity, event.getTickDelta());
                    }
                }
            } catch (Exception var10) {
                var10.printStackTrace();
            } finally {
                RenderSystem.depthMask(true);
            }
        }
    }

    private void drawHands(CustomDrawContext context, PlayerEntity player, Vector4d vec) {
        if (player != mc.player || !mc.options.getPerspective().isFirstPerson()) {
            if (!ProjectionUtil.canSee(vec)) {
                double posY = vec.w;
                float centerX = (float)ProjectionUtil.centerX(vec);

                for (ItemStack stack : player.getHandItems()) {
                    if (stack != null && !stack.isEmpty()) {
                        MutableText text = stack.getName().copy();
                        if (text.getSiblings().isEmpty()) {
                            text = text.copy()
                                .setStyle(Style.EMPTY.withColor(Zenith.getInstance().getThemeManager().getCurrentTheme().getWhite().getRGB()));
                        }

                        if (!text.getString().isEmpty()) {
                            text = TextUtil.replaceLastChar(text, "");
                        }

                        if (stack.getCount() > 1) {
                            text = text.copy()
                                .append(
                                    Text.of(" x" + stack.getCount())
                                        .copy()
                                        .setStyle(
                                            Style.EMPTY.withColor(Zenith.getInstance().getThemeManager().getCurrentTheme().getColor().getRGB())
                                        )
                                );
                        }

                        Font font = Fonts.MEDIUM.getFont(8.0F * this.scale.getCurrent());
                        posY += (double)(font.height() / 2.0F + 12.0F + 2.0F);
                        float textX = centerX - font.width(text) / 2.0F;
                        Theme theme = Zenith.getInstance().getThemeManager().getCurrentTheme();
                        ColorRGBA rectColor = Zenith.getInstance().getFriendManager().isFriend(player.getGameProfile().getName())
                            ? theme.getColor().withAlpha(theme.getForegroundLight().getAlpha())
                            : theme.getForegroundLight();
                        float actualTextWidth = font.width(text) * this.scale.getCurrent();
                        float rectWidth = actualTextWidth + 16.0F * this.scale.getCurrent();
                        float rectHeight = 12.0F * this.scale.getCurrent();
                        float rectX = textX - 8.0F * this.scale.getCurrent();
                        DrawUtil.drawBlurHudBooleanCheck(
                            context.getMatrices(),
                            rectX,
                            (float)posY,
                            rectWidth,
                            rectHeight,
                            22.0F,
                            BorderRadius.all(2.0F),
                            ColorRGBA.WHITE,
                            this.blur.isEnabled() && this.blur.isVisible(),
                            this.glow.isEnabled() && this.glow.isVisible()
                        );
                        context.drawRoundedRect(rectX, (float)posY, rectWidth, rectHeight, BorderRadius.all(2.0F), rectColor);
                        DrawUtil.drawRoundedCorner(
                            context.getMatrices(), rectX, (float)posY, rectWidth, rectHeight, 0.1F, 9.0F, theme.getColor(), BorderRadius.all(2.0F)
                        );
                        context.pushMatrix();
                        context.getMatrices().translate(textX, (float)posY + 3.0F * this.scale.getCurrent(), 0.0F);
                        context.drawText(font, text, 0.0F, 0.0F);
                        context.popMatrix();
                    }
                }
            }
        }
    }

    private void renderNameTag(CustomDrawContext context, PlayerEntity player, float tickDelta) {
        if (player != mc.player || !mc.options.getPerspective().isFirstPerson()) {
            double x = this.interpolate(player.prevX, player.getX(), tickDelta);
            double y = this.interpolate(player.prevY, player.getY(), tickDelta);
            double z = this.interpolate(player.prevZ, player.getZ(), tickDelta);
            Vec3d projected = ProjectionUtil.worldSpaceToScreenSpace(new Vec3d(x, y + (double)this.getPlayerHeight(player), z));
            if (!(projected.z <= 0.0) && !(projected.z >= 1.0)) {
                Theme theme = Zenith.getInstance().getThemeManager().getCurrentTheme();
                ColorRGBA rectColor = Zenith.getInstance().getFriendManager().isFriend(player.getGameProfile().getName())
                    ? theme.getColor().withAlpha(theme.getForegroundLight().getAlpha())
                    : theme.getForegroundLight();
                float posX = 0.0F;
                float posY = 0.0F;
                float textWidth = 0.0F;
                if (this.mojo.isSelected()) {
                    Text playerName = player != mc.player
                            && (NameProtect.getCustomName() == null || !Zenith.getInstance().getFriendManager().isFriend(player.getNameForScoreboard()))
                        ? player.getDisplayName()
                        : Text.of(NameProtect.getCustomName(player.getNameForScoreboard()));
                    if (playerName == null) {
                        return;
                    }

                    playerName = playerName.getString().contains(player.getGameProfile().getName())
                        ? TextUtil.truncateAfterSubstring(playerName, player.getGameProfile().getName(), false)
                        : TextUtil.truncateAfterSecondSpace(playerName, false);
                    Text var32 = playerName.copy()
                        .append(
                            (Text)Text.of("  " + PlayerIntersectionUtil.getHealthString(player))
                                .copy()
                                .getWithStyle(Style.EMPTY.withColor(this.getHealthColorRGBA(PlayerIntersectionUtil.getHealth(player)).getRGB()))
                                .get(0)
                        );
                    textWidth = (float)mc.textRenderer.getWidth(var32);
                    posX = (float)projected.x - textWidth / 2.0F;
                    posY = (float)projected.y - this.getPlayerHeight(player);
                    context.pushMatrix();
                    context.getMatrices().translate(posX + textWidth / 2.0F, posY + 6.5F, 0.0F);
                    context.getMatrices().scale(0.9F * this.scale.getCurrent(), 0.9F * this.scale.getCurrent(), 1.0F);
                    context.getMatrices().translate(-posX - textWidth / 2.0F, -posY - 6.5F, 0.0F);
                    float actualTextWidth = (float)mc.textRenderer.getWidth(var32) * this.scale.getCurrent();
                    float rectWidth = actualTextWidth + 12.0F * this.scale.getCurrent();
                    float rectHeight = 12.0F * this.scale.getCurrent();
                    float rectX = posX - 6.0F * this.scale.getCurrent();
                    float rectY = posY - 13.0F * this.scale.getCurrent();
                    DrawUtil.drawBlurHudBooleanCheck(
                        context.getMatrices(),
                        rectX,
                        rectY,
                        rectWidth,
                        rectHeight,
                        22.0F,
                        BorderRadius.all(2.0F),
                        ColorRGBA.WHITE,
                        this.blur.isEnabled() && this.blur.isVisible(),
                        this.glow.isEnabled() && this.glow.isVisible()
                    );
                    context.drawRoundedRect(rectX, rectY, rectWidth, rectHeight, BorderRadius.all(2.0F), rectColor);
                    DrawUtil.drawRoundedCorner(
                        context.getMatrices(), rectX, rectY, rectWidth, rectHeight, 0.1F, 9.0F, theme.getColor(), BorderRadius.all(2.0F)
                    );
                    context.pushMatrix();
                    context.getMatrices().translate(posX, posY - 13.0F * this.scale.getCurrent() + 2.0F * this.scale.getCurrent(), 0.0F);
                    context.drawText(Fonts.MEDIUM.getFont(10.0F * this.scale.getCurrent()), Text.of(var32), 0.0F, 0.0F);
                    context.popMatrix();
                } else {
                    Text playerName = player != mc.player
                            && (NameProtect.getCustomName() == null || !Zenith.getInstance().getFriendManager().isFriend(player.getNameForScoreboard()))
                        ? player.getDisplayName()
                        : Text.of(NameProtect.getCustomName(player.getGameProfile().getName()));
                    if (playerName == null) {
                        return;
                    }

                    playerName = playerName.getString().contains(player.getGameProfile().getName())
                        ? TextUtil.truncateAfterSubstring(playerName, player.getGameProfile().getName(), false)
                        : TextUtil.truncateAfterSecondSpace(playerName, false);
                    Text finalText = Text.of("");

                    for (Text text : playerName.getSiblings()) {
                        finalText = finalText.copy()
                            .append(
                                text.copy()
                                    .setStyle(
                                        text.getStyle().getColor() == null
                                            ? Style.EMPTY.withColor(theme.getWhite().getRGB())
                                            : text.getStyle()
                                    )
                            );
                    }

                    float hp = PlayerIntersectionUtil.getHealth(player);
                    String health = PlayerIntersectionUtil.getHealthString(hp);
                    Font font = Fonts.MEDIUM.getFont(8.0F * this.scale.getCurrent());
                    textWidth = font.width(finalText) + 8.0F + font.width(health);
                    posX = (float)projected.x - textWidth / 2.0F;
                    posY = (float)projected.y - this.getPlayerHeight(player);
                    context.pushMatrix();
                    context.getMatrices().translate(posX + textWidth / 2.0F, posY + 6.5F, 0.0F);
                    context.getMatrices().scale(0.9F * this.scale.getCurrent(), 0.9F * this.scale.getCurrent(), 1.0F);
                    context.getMatrices().translate(-posX - textWidth / 2.0F, -posY - 6.5F, 0.0F);
                    float actualNameWidth = font.width(finalText) * this.scale.getCurrent();
                    float actualHealthWidth = font.width(health) * this.scale.getCurrent();
                    float actualTotalWidth = actualNameWidth + 8.0F * this.scale.getCurrent() + actualHealthWidth;
                    float rectWidth2 = actualTotalWidth + 16.0F * this.scale.getCurrent();
                    float rectHeight2 = 12.0F * this.scale.getCurrent();
                    float rectX2 = posX - 8.0F * this.scale.getCurrent();
                    float rectY2 = posY - 13.0F * this.scale.getCurrent();
                    DrawUtil.drawBlurHudBooleanCheck(
                        context.getMatrices(),
                        rectX2,
                        rectY2,
                        rectWidth2,
                        rectHeight2,
                        22.0F,
                        BorderRadius.all(2.0F),
                        ColorRGBA.WHITE,
                        this.blur.isEnabled() && this.blur.isVisible(),
                        this.glow.isEnabled() && this.glow.isVisible()
                    );
                    context.drawRoundedRect(rectX2, rectY2, rectWidth2, rectHeight2, BorderRadius.all(2.0F), rectColor);
                    DrawUtil.drawRoundedCorner(
                        context.getMatrices(), rectX2, rectY2, rectWidth2, rectHeight2, 0.1F, 9.0F, theme.getColor(), BorderRadius.all(2.0F)
                    );
                    context.pushMatrix();
                    context.getMatrices().translate(posX, posY - 13.0F * this.scale.getCurrent() + 3.0F * this.scale.getCurrent(), 0.0F);
                    context.drawText(font, finalText, 0.0F, 0.0F);
                    context.drawText(font, health, actualNameWidth + 8.0F * this.scale.getCurrent(), 0.0F, this.getHealthColorRGBA(hp));
                    context.popMatrix();
                }

                if (this.elements.isEnable(2)) {
                    ArrayList<ItemStack> stacks = new ArrayList<>();
                    stacks.add(player.getOffHandStack());
                    stacks.addAll(player.getInventory().armor);
                    stacks.add(player.getMainHandStack());
                    int nonEmpty = (int)stacks.stream().filter(stackx -> !stackx.isEmpty()).count();
                    if (nonEmpty > 0) {
                        float totalWidth = (float)(nonEmpty * 18) * this.scale.getCurrent();
                        float centerX = posX + textWidth / 2.0F;
                        float rectX = centerX - totalWidth / 2.0F - 4.0F * this.scale.getCurrent();
                        float rectY = posY - 35.0F * this.scale.getCurrent();
                        float rectHeight = 18.0F * this.scale.getCurrent();
                        DrawUtil.drawBlurHudBooleanCheck(
                            context.getMatrices(),
                            rectX,
                            rectY,
                            totalWidth,
                            rectHeight,
                            22.0F,
                            BorderRadius.all(2.0F),
                            ColorRGBA.WHITE,
                            this.blur.isEnabled() && this.blur.isVisible(),
                            this.glow.isEnabled() && this.glow.isVisible()
                        );
                        context.drawRoundedRect(rectX, rectY, totalWidth, rectHeight, BorderRadius.all(2.0F), rectColor);
                        DrawUtil.drawRoundedCorner(
                            context.getMatrices(), rectX, rectY, totalWidth, rectHeight, 0.1F, 10.0F, theme.getColor(), BorderRadius.all(2.0F)
                        );
                        float currentOffset = 0.0F;

                        for (ItemStack stack : stacks) {
                            if (!stack.isEmpty()) {
                                context.pushMatrix();
                                context.getMatrices().translate(centerX - totalWidth / 2.0F + currentOffset, rectY, 0.0F);
                                context.getMatrices().scale(this.scale.getCurrent(), this.scale.getCurrent(), 1.0F);
                                DiffuseLighting.disableGuiDepthLighting();
                                context.drawItem(stack, 0, 1);
                                context.popMatrix();
                                currentOffset += 18.0F * this.scale.getCurrent();
                            }
                        }
                    }
                }

                context.popMatrix();
            }
        }
    }

    private void renderItemESP(CustomDrawContext context, ItemEntity ent, float tickDelta) {
        Vec3d[] corners = this.getPoints(ent, tickDelta);
        Vector4d screenBB = null;

        for (Vec3d v : corners) {
            Vec3d p = ProjectionUtil.worldSpaceToScreenSpace(v);
            if (p.z > 0.0 && p.z < 1.0) {
                if (screenBB == null) {
                    screenBB = new Vector4d(p.x, p.y, p.x, p.y);
                }

                screenBB.x = Math.min(screenBB.x, p.x);
                screenBB.y = Math.min(screenBB.y, p.y);
                screenBB.z = Math.max(screenBB.z, p.x);
                screenBB.w = Math.max(screenBB.w, p.y);
            }
        }

        if (screenBB != null) {
            Text label = ent.getStack().getName().copy();
            if (label.getSiblings().isEmpty()) {
                label = label.copy()
                    .setStyle(Style.EMPTY.withColor(Zenith.getInstance().getThemeManager().getCurrentTheme().getWhite().getRGB()));
            }

            if (!label.getString().isEmpty() && label.getString().charAt(label.getString().length() - 1) == ' ') {
                label = TextUtil.replaceLastChar(label, "");
            }

            if (ent.getStack().getCount() > 1) {
                label = label.copy()
                    .append(
                        Text.of(" x" + ent.getStack().getCount())
                            .copy()
                            .setStyle(Style.EMPTY.withColor(Zenith.getInstance().getThemeManager().getCurrentTheme().getColor().getRGB()))
                    );
            }

            Theme theme = Zenith.getInstance().getThemeManager().getCurrentTheme();
            Font font = Fonts.MEDIUM.getFont(10.0F * this.scale.getCurrent());
            float padX = 8.0F * this.scale.getCurrent();
            float padY = 12.0F * this.scale.getCurrent();
            float textW = font.width(label) * this.scale.getCurrent();
            float rectW = textW + padX * 2.0F + 11.2F * this.scale.getCurrent() + padX;
            float textH = 10.0F * this.scale.getCurrent();
            float boxMinX = (float)screenBB.x;
            float boxMaxX = (float)screenBB.z;
            float boxMinY = (float)screenBB.y;
            float posX = boxMinX + (boxMaxX - boxMinX) / 2.0F - rectW / 2.0F;
            float posY = boxMinY - 13.0F;
            float rectX = posX - padX;
            context.pushMatrix();
            context.getMatrices().translate(rectX + rectW / 2.0F, posY + 6.5F, 0.0F);
            context.getMatrices().scale(0.9F * this.scale.getCurrent(), 0.9F * this.scale.getCurrent(), 1.0F);
            context.getMatrices().translate(-(rectX + rectW / 2.0F), -(posY + 6.5F), 0.0F);
            DrawUtil.drawBlurHudBooleanCheck(
                context.getMatrices(),
                rectX,
                posY,
                rectW,
                padY,
                22.0F,
                BorderRadius.all(2.0F),
                ColorRGBA.WHITE,
                this.blur.isEnabled() && this.blur.isVisible(),
                this.glow.isEnabled() && this.glow.isVisible()
            );
            ColorRGBA rectColor = theme.getForegroundLight();
            context.drawRoundedRect(rectX, posY, rectW, padY, BorderRadius.all(2.0F), rectColor);
            DrawUtil.drawRoundedCorner(context.getMatrices(), rectX, posY, rectW, padY, 0.1F, 9.0F, theme.getColor(), BorderRadius.all(2.0F));
            context.pushMatrix();
            context.getMatrices()
                .translate(posX + 11.2F * this.scale.getCurrent() + 8.0F * this.scale.getCurrent(), posY + 2.0F * this.scale.getCurrent(), 0.0F);
            context.drawText(font, label, 0.0F, 0.0F);
            context.popMatrix();
            float itemX = rectX + padX;
            context.pushMatrix();
            context.getMatrices().translate(itemX, posY, 0.0F);
            context.getMatrices().scale(0.7F * this.scale.getCurrent(), 0.7F * this.scale.getCurrent(), 1.0F);
            DiffuseLighting.disableGuiDepthLighting();
            context.drawItem(ent.getStack(), 0, 0);
            context.popMatrix();
            context.popMatrix();
        }
    }

    private void renderEntityBox(CustomDrawContext context, Entity entity, float tickDelta) {
        if (entity != mc.player || !mc.options.getPerspective().isFirstPerson()) {
            Vector4d vec4d = ProjectionUtil.getVector4D(entity);
            if (!ProjectionUtil.canSee(vec4d)) {
                boolean var10001;
                label19: {
                    if (entity instanceof PlayerEntity player && Zenith.getInstance().getFriendManager().isFriend(player.getGameProfile().getName())) {
                        var10001 = true;
                        break label19;
                    }

                    var10001 = false;
                }

                this.drawFlatBox(var10001, vec4d);
            }
        }
    }

    private void drawFlatBox(boolean friend, Vector4d vec) {
        int client1 = !friend
            ? Zenith.getInstance().getThemeManager().getClientColor(0).getRGB()
            : Zenith.getInstance().getThemeManager().getCurrentTheme().getFriendColor().getRGB();
        int client2 = !friend
            ? Zenith.getInstance().getThemeManager().getClientColor(90).getRGB()
            : Zenith.getInstance().getThemeManager().getCurrentTheme().getFriendColor().getRGB();
        int client3 = !friend
            ? Zenith.getInstance().getThemeManager().getClientColor(180).getRGB()
            : Zenith.getInstance().getThemeManager().getCurrentTheme().getFriendColor().getRGB();
        int client4 = !friend
            ? Zenith.getInstance().getThemeManager().getClientColor(270).getRGB()
            : Zenith.getInstance().getThemeManager().getCurrentTheme().getFriendColor().getRGB();
        float posX = (float)vec.x;
        float posY = (float)vec.y;
        float endPosX = (float)vec.z;
        float endPosY = (float)vec.w;
        float baseSize = (endPosX - posX) / 3.0F;
        float size = baseSize * this.scale.getCurrent();
        float thickness = 2.0F * this.scale.getCurrent();
        float offsetX = (baseSize - size) / 2.0F;
        float offsetY = (baseSize - size) / 2.0F;
        Render2DUtil.drawQuad(posX - thickness + offsetX, posY - thickness + offsetY, size, thickness, client1);
        Render2DUtil.drawQuad(posX - thickness + offsetX, posY + offsetY, thickness, size + thickness, client1);
        Render2DUtil.drawQuad(posX - thickness + offsetX, endPosY - size - thickness + offsetY, thickness, size, client2);
        Render2DUtil.drawQuad(posX - thickness + offsetX, endPosY - thickness + offsetY, thickness, thickness, client2);
        Render2DUtil.drawQuad(endPosX - size + thickness * 2.0F + offsetX, posY - thickness + offsetY, size, thickness, client3);
        Render2DUtil.drawQuad(endPosX + thickness + offsetX, posY + offsetY, thickness, size + thickness, client3);
        Render2DUtil.drawQuad(endPosX + thickness + offsetX, endPosY - size - thickness + offsetY, thickness, size, client4);
        Render2DUtil.drawQuad(endPosX - size + thickness * 2.0F + offsetX, endPosY - thickness + offsetY, thickness, thickness, client4);
    }

    private float getPlayerHeight(PlayerEntity player) {
        return (float)player.getBoundingBox().getLengthY() + 0.2F;
    }

    private double interpolate(double prev, double current, float delta) {
        return prev + (current - prev) * (double)delta;
    }

    private Vec3d[] getPoints(Entity entity, float tickDelta) {
        double x = entity.prevX + (entity.getX() - entity.prevX) * (double)tickDelta;
        double y = entity.prevY + (entity.getY() - entity.prevY) * (double)tickDelta;
        double z = entity.prevZ + (entity.getZ() - entity.prevZ) * (double)tickDelta;
        Box box = entity.getBoundingBox();
        Box shifted = new Box(
            box.minX - entity.getX() + x - 0.05,
            box.minY - entity.getY() + y,
            box.minZ - entity.getZ() + z - 0.05,
            box.maxX - entity.getX() + x + 0.05,
            box.maxY - entity.getY() + y + 0.15,
            box.maxZ - entity.getZ() + z + 0.05
        );
        return new Vec3d[]{
            new Vec3d(shifted.minX, shifted.minY, shifted.minZ),
            new Vec3d(shifted.minX, shifted.maxY, shifted.minZ),
            new Vec3d(shifted.maxX, shifted.minY, shifted.minZ),
            new Vec3d(shifted.maxX, shifted.maxY, shifted.minZ),
            new Vec3d(shifted.minX, shifted.minY, shifted.maxZ),
            new Vec3d(shifted.minX, shifted.maxY, shifted.maxZ),
            new Vec3d(shifted.maxX, shifted.minY, shifted.maxZ),
            new Vec3d(shifted.maxX, shifted.maxY, shifted.maxZ)
        };
    }

    private ColorRGBA getHealthColorRGBA(float health) {
        if (health <= 7.0F) {
            return new ColorRGBA(255, 0, 0, 255);
        } else {
            return health <= 15.0F ? new ColorRGBA(255, 255, 0, 255) : new ColorRGBA(0, 255, 0, 255);
        }
    }
}
