package sh.grimmer.bettershulkers.render;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import com.mojang.serialization.Codec;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.blockentity.state.ShulkerBoxRenderState;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.state.CameraRenderState;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.Direction;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.util.FormattedCharSequence;
import net.minecraft.world.item.ItemStack;
import sh.grimmer.bettershulkers.interfaces.BsShulkerBoxRenderState;
import sh.grimmer.bettershulkers.util.ItemRenderHelper;

import org.jetbrains.annotations.Nullable;

public final class ShulkerHintRenderer {

    private static final DataComponentType<Boolean> SHULKER_RENDER_MARKER = DataComponentType.<Boolean>builder().persistent(Codec.BOOL).build();

    private ShulkerHintRenderer() {
    }

    public static void submitBlockHint(ShulkerBoxRenderState renderState, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState camera) {
        if (!(renderState instanceof BsShulkerBoxRenderState bsState)) {
            throw new IllegalStateException("ShulkerBoxRenderState does not implement BsShulkerBoxRenderState");
        }
        submitHint(
                renderState.direction, renderState.progress,
                bsState.betterShulkers$getDisplayItem(), bsState.betterShulkers$getLabel(),
                renderState.lightCoords, poseStack, collector, 1F
        );
    }

    public static void submitItemHint(ShulkerHintData hintData, PoseStack poseStack, SubmitNodeCollector collector, int light, float itemScale) {
        ItemStackRenderState renderState = ItemRenderHelper.createRenderState(
                Minecraft.getInstance().level, null,
                createMarkedStack(hintData.getDisplayItem())
        );
        submitHint(Direction.UP, 0F, renderState, hintData.getLabelFormatted(), light, poseStack, collector, itemScale);
    }

    private static void submitHint(
            Direction direction, float progress,
            @Nullable ItemStackRenderState displayItem, @Nullable FormattedCharSequence label,
            int lightCoords, PoseStack poseStack, SubmitNodeCollector collector, float itemScale
    ) {
        Minecraft mc = Minecraft.getInstance();

        poseStack.pushPose();
        poseStack.translate(0.5D, 0.5D, 0.5D);
        poseStack.mulPose(direction.getRotation());
        poseStack.translate(0D, 0.5D, 0D);
        poseStack.translate(0F, progress * 0.5F, 0F);
        poseStack.rotateAround(Axis.YP.rotationDegrees(-270F * progress), 0F, 1F, 0F);
        poseStack.rotateAround(Axis.XP.rotationDegrees(-90F), 1F, 0F, 0F);

        if (displayItem != null) {
            poseStack.pushPose();
            poseStack.rotateAround(Axis.YP.rotationDegrees(180F), 0F, 1F, 0F);
            if (label != null) {
                poseStack.translate(0F, 2F / 16F, 0F);
                poseStack.scale(12F / 16F, 12F / 16F, 12F / 16F);
            }
            if (itemScale != 1F) {
                poseStack.scale(itemScale, itemScale, itemScale);
            }
            displayItem.submit(poseStack, collector, lightCoords, OverlayTexture.NO_OVERLAY, 0);
            poseStack.popPose();
        }

        if (label != null) {
            poseStack.pushPose();
            if (displayItem != null) {
                poseStack.translate(0F, -6F / 16F, 0F);
            }
            int width = mc.font.width(label);
            float textScale = Math.min(0.8F / width, 0.02F);
            poseStack.scale(textScale, textScale, textScale);
            poseStack.translate(0F, mc.font.lineHeight / 2F, 0F);
            poseStack.rotateAround(Axis.XP.rotationDegrees(180F), 1F, 0F, 0F);
            collector.submitText(poseStack, -width / 2F, 0F, label, false, Font.DisplayMode.POLYGON_OFFSET, lightCoords, 0xFFFFFFFF, 0x00000000, 0xFF000000);
            poseStack.popPose();
        }

        poseStack.popPose();
    }

    public static boolean isMarkedStack(ItemStack stack) {
        return stack.getComponents().getOrDefault(SHULKER_RENDER_MARKER, false);
    }

    @Nullable
    public static ItemStack createMarkedStack(@Nullable ItemStack source) {
        if (source == null) {
            return null;
        }
        ItemStack copy = source.copy();
        copy.applyComponents(DataComponentPatch.builder().set(SHULKER_RENDER_MARKER, true).build());
        return copy;
    }
}
