package fr.bglands.client.fabric;

import fr.bglands.client.protocol.FormField;
import fr.bglands.client.protocol.OpenForm;
import fr.bglands.client.protocol.UiResult;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;

final class BgLandsFormScreen extends Screen {
    private static final int DESIGN_WIDTH = 400;
    private static final int DESIGN_HEIGHT = 300;
    private static final Identifier BACKGROUND =
            Identifier.fromNamespaceAndPath("bglands", "textures/gui/frame_main.png");
    private static final Identifier LOGO =
            Identifier.fromNamespaceAndPath("bglands", "textures/gui/logo.png");

    private final OpenForm definition;
    private final BgLandsConnection connection;
    private final Map<String, EditBox> inputs = new LinkedHashMap<>();

    private float scale;
    private int panelX;
    private int panelY;
    private BgLandsButton submitButton;
    private String pendingRequest;
    private Component resultMessage = Component.empty();
    private int resultColor = 0xFFFFFFFF;

    BgLandsFormScreen(OpenForm definition, BgLandsConnection connection) {
        super(Component.literal(stripLegacy(definition.title())));
        this.definition = definition;
        this.connection = connection;
    }

    @Override
    protected void init() {
        clearWidgets();
        inputs.clear();
        computeLayout();

        int fieldCount = definition.fields().size();
        int columns = fieldCount > 4 ? 2 : 1;
        int fieldWidth = columns == 1 ? sw(236) : sw(128);
        int fieldHeight = Math.max(18, sh(20));
        for (int index = 0; index < fieldCount; index++) {
            FormField field = definition.fields().get(index);
            int column = index % columns;
            int row = index / columns;
            int x = columns == 1 ? px(106) : px(78 + column * 146);
            int y = py(139 + row * 29);
            EditBox input = new EditBox(
                    font,
                    x, y,
                    fieldWidth, fieldHeight,
                    Component.literal(stripLegacy(field.label()))
            );
            input.setMaxLength(field.maxLength());
            input.setHint(Component.literal(stripLegacy(field.placeholder())));
            inputs.put(field.id(), addRenderableWidget(input));
        }

        submitButton = addRenderableWidget(new BgLandsButton(
                px(125), py(255), sw(120), Math.max(20, sh(26)),
                Component.literal("Valider"), Component.literal("Envoyer ce formulaire"),
                "green", Identifier.fromNamespaceAndPath("bglands", "textures/gui/icons/game.png"),
                this::submit
        ));
        addRenderableWidget(new BgLandsButton(
                px(252), py(255), sw(70), Math.max(20, sh(26)),
                Component.literal("Fermer"), Component.literal("Annuler"),
                "red", Identifier.fromNamespaceAndPath("bglands", "textures/gui/icons/cancel.png"),
                this::onClose
        ));
    }

    @Override
    public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) {
        graphics.fill(0, 0, width, height, 0xB5000000);
        graphics.blit(
                RenderPipelines.GUI_TEXTURED,
                BACKGROUND,
                panelX, panelY,
                0, 0,
                sw(DESIGN_WIDTH), sh(DESIGN_HEIGHT),
                DESIGN_WIDTH, DESIGN_HEIGHT,
                DESIGN_WIDTH, DESIGN_HEIGHT
        );
        graphics.blit(
                RenderPipelines.GUI_TEXTURED,
                LOGO,
                px(136), py(20),
                0, 0,
                sw(180), sh(60),
                543, 181,
                543, 181
        );
        super.extractRenderState(graphics, mouseX, mouseY, delta);

        String title = stripLegacy(definition.title());
        int titleX = px(78) + Math.max(0, (sw(288) - font.width(title)) / 2);
        graphics.text(font, title, titleX, py(99), 0xFF63F27A, true);

        List<net.minecraft.util.FormattedCharSequence> instructions = font.split(
                Component.literal(stripLegacy(definition.instruction())), sw(270)
        );
        int instructionY = py(114);
        for (int index = 0; index < Math.min(2, instructions.size()); index++) {
            var line = instructions.get(index);
            int lineX = px(87) + Math.max(0, (sw(270) - font.width(line)) / 2);
            graphics.text(font, line, lineX, instructionY, 0xFFE6E8ED, false);
            instructionY += font.lineHeight + 1;
        }

        int fieldCount = definition.fields().size();
        int columns = fieldCount > 4 ? 2 : 1;
        for (int index = 0; index < fieldCount; index++) {
            FormField field = definition.fields().get(index);
            int column = index % columns;
            int row = index / columns;
            int x = columns == 1 ? px(106) : px(78 + column * 146);
            int y = py(139 + row * 29) - font.lineHeight - 2;
            graphics.text(font, stripLegacy(field.label()), x, y, 0xFFC8CDD8, false);
        }

        if (!resultMessage.getString().isBlank()) {
            String text = font.plainSubstrByWidth(resultMessage.getString(), sw(250));
            int x = px(98) + Math.max(0, (sw(250) - font.width(text)) / 2);
            graphics.text(font, text, x, py(245), resultColor, false);
        }
    }

    @Override
    public void onClose() {
        if (minecraft != null) {
            minecraft.gui.setScreen(null);
        }
    }

    void acceptResult(UiResult result) {
        if (pendingRequest == null || !pendingRequest.equals(result.requestId())) {
            return;
        }
        pendingRequest = null;
        submitButton.active = true;
        resultMessage = Component.literal(stripLegacy(result.message()));
        String status = result.status().toLowerCase(Locale.ROOT);
        if (status.equals("accepted")) {
            onClose();
            return;
        }
        resultColor = status.equals("ok") || status.equals("success")
                ? 0xFF74F58C
                : 0xFFFF667A;
    }

    private void submit() {
        if (pendingRequest != null) {
            return;
        }
        Map<String, String> values = new LinkedHashMap<>();
        inputs.forEach((id, input) -> values.put(id, input.getValue()));
        Optional<String> requestId = connection.submit(definition, values);
        if (requestId.isEmpty()) {
            resultMessage = Component.literal("Formulaire indisponible : utilise l'interface serveur.");
            resultColor = 0xFFFFC857;
            return;
        }
        pendingRequest = requestId.get();
        submitButton.active = false;
        resultMessage = Component.literal("Envoi…");
        resultColor = 0xFFB9C0CD;
    }

    private void computeLayout() {
        float availableX = Math.max(1, width - 12) / (float) DESIGN_WIDTH;
        float availableY = Math.max(1, height - 12) / (float) DESIGN_HEIGHT;
        scale = Math.max(0.60F, Math.min(1.50F, Math.min(availableX, availableY)));
        panelX = (width - sw(DESIGN_WIDTH)) / 2;
        panelY = (height - sh(DESIGN_HEIGHT)) / 2;
    }

    private int px(int designX) {
        return panelX + sw(designX);
    }

    private int py(int designY) {
        return panelY + sh(designY);
    }

    private int sw(int value) {
        return Math.round(value * scale);
    }

    private int sh(int value) {
        return Math.round(value * scale);
    }

    private static String stripLegacy(String value) {
        return value == null ? "" : value.replaceAll("(?i)§[0-9A-FK-ORX]", "");
    }
}
