package sh.grimmer.bettershulkers.tooltip;

import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.core.NonNullList;
import net.minecraft.resources.Identifier;
import net.minecraft.world.item.ItemStack;
import sh.grimmer.bettershulkers.BetterShulkers;

public class ContainerTooltipRenderer implements ClientTooltipComponent {

    public static final Identifier TEXTURE = Identifier.fromNamespaceAndPath(BetterShulkers.MOD_ID, "textures/gui/container/slot.png");

    private static final int MARGIN_Y = 4;
    private static final int BORDER = 1;
    private static final int TEX_SIZE = 32;
    private static final int SLOT_W = 18;
    private static final int SLOT_H = 18;

    private final int gridWidth;
    private final int gridHeight;
    private final NonNullList<ItemStack> items;

    public ContainerTooltipRenderer(ContainerTooltip tooltip) {
        this.gridWidth = tooltip.getWidth();
        this.gridHeight = tooltip.getHeight();
        this.items = tooltip.getItems();
    }

    @Override
    public int getHeight(Font font) {
        return gridHeight * SLOT_H + 2 * BORDER + MARGIN_Y;
    }

    @Override
    public int getWidth(Font font) {
        return gridWidth * SLOT_W + 2;
    }

    @Override
    public void renderImage(Font font, int tooltipX, int tooltipY, int i1, int i2, GuiGraphics gfx) {
        int slot = 0;
        for (int y = 0; y < gridHeight; y++) {
            for (int x = 0; x < gridWidth; x++) {
                int px = tooltipX + x * SLOT_W + BORDER;
                int py = tooltipY + y * SLOT_H + BORDER;
                renderSlot(px, py, slot++, font, gfx);
            }
        }
        renderBorder(tooltipX, tooltipY, gfx);
    }

    private void renderSlot(int x, int y, int slotIndex, Font font, GuiGraphics gfx) {
        ItemStack stack = slotIndex < items.size() ? items.get(slotIndex) : ItemStack.EMPTY;
        blit(gfx, x, y, Sprite.SLOT);
        gfx.renderItem(stack, x + BORDER, y + BORDER, slotIndex);
        gfx.renderItemDecorations(font, stack, x + BORDER, y + BORDER);
    }

    private void renderBorder(int x, int y, GuiGraphics gfx) {
        blit(gfx, x, y, Sprite.CORNER);
        blit(gfx, x + gridWidth * SLOT_W + BORDER, y, Sprite.CORNER);

        for (int i = 0; i < gridWidth; i++) {
            blit(gfx, x + BORDER + i * SLOT_W, y, Sprite.HORIZONTAL);
            blit(gfx, x + BORDER + i * SLOT_W, y + gridHeight * SLOT_H + 1, Sprite.HORIZONTAL);
        }

        for (int i = 0; i < gridHeight; i++) {
            blit(gfx, x, y + i * SLOT_H + BORDER, Sprite.VERTICAL);
            blit(gfx, x + gridWidth * SLOT_W + BORDER, y + i * SLOT_H + BORDER, Sprite.VERTICAL);
        }

        blit(gfx, x, y + gridHeight * SLOT_H + 1, Sprite.CORNER);
        blit(gfx, x + gridWidth * SLOT_W + BORDER, y + gridHeight * SLOT_H + 1, Sprite.CORNER);
    }

    private void blit(GuiGraphics gfx, int x, int y, Sprite sprite) {
        gfx.blit(RenderPipelines.GUI_TEXTURED, TEXTURE, x, y, (float) sprite.u, (float) sprite.v, sprite.w, sprite.h, TEX_SIZE, TEX_SIZE);
    }

    enum Sprite {
        SLOT(0, 0, SLOT_W, SLOT_H),
        HORIZONTAL(0, SLOT_H, SLOT_W, BORDER),
        VERTICAL(SLOT_W, 0, BORDER, SLOT_H),
        CORNER(SLOT_W, SLOT_H, BORDER, BORDER);

        final int u, v, w, h;

        Sprite(int u, int v, int w, int h) {
            this.u = u;
            this.v = v;
            this.w = w;
            this.h = h;
        }
    }
}
