package fr.bglands.client.fabric;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.input.KeyEvent;
import net.minecraft.client.input.MouseButtonEvent;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;

import java.util.Locale;

final class BgLandsButton extends AbstractWidget {
    private static final int TEXTURE_WIDTH = 120;
    private static final int TEXTURE_HEIGHT = 32;

    private final Identifier normalTexture;
    private final Identifier hoverTexture;
    private final Identifier icon;
    private final Component description;
    private final Runnable onPress;
    private final int textColor;
    private final int authoredFontSize;
    private final String textAlign;

    BgLandsButton(
            int x,
            int y,
            int width,
            int height,
            Component label,
            Component description,
            String color,
            Identifier icon,
            Runnable onPress
    ) {
        this(x, y, width, height, label, description, color, null, icon, 0xFFFFFFFF, 0, "center", onPress);
    }

    BgLandsButton(
            int x,
            int y,
            int width,
            int height,
            Component label,
            Component description,
            String color,
            String buttonAsset,
            Identifier icon,
            int textColor,
            int authoredFontSize,
            String textAlign,
            Runnable onPress
    ) {
        super(x, y, width, height, label);
        String style = assetStyleName(buttonAsset, color);
        this.normalTexture = Identifier.fromNamespaceAndPath(
                "bglands", "textures/gui/buttons/button_" + style + ".png"
        );
        this.hoverTexture = Identifier.fromNamespaceAndPath(
                "bglands", "textures/gui/buttons/button_" + style + "_highlight.png"
        );
        this.icon = icon;
        this.description = description;
        this.onPress = onPress;
        this.textColor = textColor;
        this.authoredFontSize = authoredFontSize;
        this.textAlign = textAlign == null ? "center" : textAlign;
    }

    @Override
    public void onClick(MouseButtonEvent event, boolean doubleClick) {
        if (active) {
            onPress.run();
        }
    }

    @Override
    public boolean keyPressed(KeyEvent event) {
        if (!active || !event.isSelection()) {
            return false;
        }
        playDownSound(Minecraft.getInstance().getSoundManager());
        onPress.run();
        return true;
    }

    @Override
    protected void extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) {
        Identifier texture = isHovered() && active ? hoverTexture : normalTexture;
        graphics.blit(
                RenderPipelines.GUI_TEXTURED,
                texture,
                getX(), getY(),
                0, 0,
                width, height,
                TEXTURE_WIDTH, TEXTURE_HEIGHT,
                TEXTURE_WIDTH, TEXTURE_HEIGHT
        );

        int iconSize = Math.min(16, Math.max(10, height - 8));
        int textStart = getX() + 8;
        if (icon != null) {
            int iconY = getY() + (height - iconSize) / 2;
            graphics.blit(
                    RenderPipelines.GUI_TEXTURED,
                    icon,
                    getX() + 7, iconY,
                    0, 0,
                    iconSize, iconSize,
                    16, 16,
                    16, 16
            );
            textStart += iconSize + 4;
        }

        var font = Minecraft.getInstance().font;
        int available = Math.max(8, getX() + width - textStart - 7);
        String label = getMessage().getString();
        float textScale = authoredFontSize <= 0
                ? 1.0F
                : Math.max(0.35F, Math.min(3.0F, authoredFontSize / (float) font.lineHeight));
        int logicalAvailable = Math.max(1, Math.round(available / textScale));
        if (font.width(label) > logicalAvailable) {
            label = font.plainSubstrByWidth(label, Math.max(1, logicalAvailable - font.width("…"))) + "…";
        }
        int renderedWidth = Math.round(font.width(label) * textScale);
        int textX = switch (textAlign) {
            case "left" -> textStart;
            case "right" -> textStart + Math.max(0, available - renderedWidth);
            default -> textStart + Math.max(0, (available - renderedWidth) / 2);
        };
        int renderedHeight = Math.round(font.lineHeight * textScale);
        int textY = getY() + Math.max(0, (height - renderedHeight) / 2);
        int color = active ? textColor : 0xFF818181;
        graphics.pose().pushMatrix();
        graphics.pose().translate(textX, textY);
        graphics.pose().scale(textScale, textScale);
        graphics.text(font, label, 0, 0, color, true);
        graphics.pose().popMatrix();
    }

    @Override
    protected void updateWidgetNarration(NarrationElementOutput output) {
        output.add(NarratedElementType.TITLE, createNarrationMessage());
        if (!description.getString().isBlank()) {
            output.add(NarratedElementType.HINT, description);
        }
    }

    Component description() {
        return description;
    }

    private static String styleName(String rawColor) {
        String color = rawColor == null ? "" : rawColor.toLowerCase(Locale.ROOT);
        if (color.contains("red") || color.equals("#ff4055") || color.equals("#ff3344")) {
            return "red";
        }
        if (color.contains("purple") || color.contains("violet") || color.equals("#be62ff")) {
            return "purple";
        }
        if (color.contains("blue") || color.contains("cyan") || color.equals("#42d9ff")) {
            return "blue";
        }
        if (color.contains("yellow") || color.contains("gold") || color.equals("#ffca28")) {
            return "yellow";
        }
        if (color.contains("white") || color.equals("#ffffff")) {
            return "white";
        }
        if (color.matches("#[0-9a-f]{6}")) {
            int rgb = Integer.parseInt(color.substring(1), 16);
            int red = (rgb >> 16) & 0xFF;
            int green = (rgb >> 8) & 0xFF;
            int blue = rgb & 0xFF;
            int max = Math.max(red, Math.max(green, blue));
            int min = Math.min(red, Math.min(green, blue));
            if (max - min < 28) {
                return "white";
            }
            if (green > red && green >= blue) {
                return "green";
            }
            if (red >= green && green > blue + 24) {
                return "yellow";
            }
            if (blue > red && blue > green) {
                return red > green + 24 ? "purple" : "blue";
            }
            if (red > green + 24) {
                return blue > green + 24 ? "purple" : "red";
            }
        }
        return "green";
    }

    private static String assetStyleName(String rawAsset, String fallbackColor) {
        if (rawAsset != null) {
            String asset = rawAsset.toLowerCase(Locale.ROOT);
            for (String style : new String[]{"blue", "green", "purple", "red", "white", "yellow"}) {
                if (asset.equals("/assets/buttons/button_" + style + ".png")) {
                    return style;
                }
            }
        }
        return styleName(fallbackColor);
    }
}
