package fr.bglands.client.fabric;

import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.hud.VanillaHudElements;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.core.Direction;
import net.minecraft.resources.Identifier;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Locale;

final class BgLandsLauncherHud {
    private static final int PANEL = 0xCC090D0B;
    private static final int BORDER = 0xFF334238;
    private static final int GOLD = 0xFFF4B72B;
    private static final int GREEN = 0xFF63C174;
    private static final int TEXT = 0xFFF4F1E8;
    private static final int MUTED = 0xFFB7C0B8;
    private static final Deque<Long> LEFT_CLICKS = new ArrayDeque<>();
    private static final Deque<Long> RIGHT_CLICKS = new ArrayDeque<>();
    private static boolean previousLeft;
    private static boolean previousRight;

    private BgLandsLauncherHud() {}

    static void register() {
        ClientTickEvents.END_CLIENT_TICK.register(BgLandsLauncherHud::tick);
        HudElementRegistry.attachElementAfter(
                VanillaHudElements.MISC_OVERLAYS,
                Identifier.fromNamespaceAndPath(BgLandsClient.MOD_ID, "launcher_hud"),
                BgLandsLauncherHud::render
        );
    }

    private static boolean enabled(String module, boolean fallback) {
        return Boolean.parseBoolean(System.getProperty("bglands.module." + module, Boolean.toString(fallback)));
    }

    private static void tick(Minecraft client) {
        if (client.player == null) {
            previousLeft = false;
            previousRight = false;
            LEFT_CLICKS.clear();
            RIGHT_CLICKS.clear();
            return;
        }
        long now = System.currentTimeMillis();
        boolean left = client.options.keyAttack.isDown();
        boolean right = client.options.keyUse.isDown();
        if (left && !previousLeft) LEFT_CLICKS.addLast(now);
        if (right && !previousRight) RIGHT_CLICKS.addLast(now);
        previousLeft = left;
        previousRight = right;
        prune(LEFT_CLICKS, now);
        prune(RIGHT_CLICKS, now);
    }

    private static void prune(Deque<Long> clicks, long now) {
        while (!clicks.isEmpty() && now - clicks.peekFirst() > 1_000) clicks.removeFirst();
    }

    private static void render(GuiGraphicsExtractor graphics, net.minecraft.client.DeltaTracker ignored) {
        Minecraft client = Minecraft.getInstance();
        if (client.player == null || client.level == null) return;

        if (enabled("keystrokes", true) || enabled("cps", true)) renderKeys(graphics, client);

        int right = graphics.guiWidth() - 10;
        int y = 10;
        if (enabled("minimap", false)) {
            renderMinimap(graphics, client, right - 82, y);
            y += 90;
        }
        if (enabled("ping", true)) {
            int ping = 0;
            if (client.getConnection() != null) {
                PlayerInfo player = client.getConnection().getPlayerInfo(client.player.getUUID());
                if (player != null) ping = Math.max(0, player.getLatency());
            }
            y = renderMetric(graphics, client, right, y, "PING", ping + " ms", ping < 90 ? GREEN : GOLD);
        }
        if (enabled("resources", true)) {
            Runtime runtime = Runtime.getRuntime();
            long usedMb = (runtime.totalMemory() - runtime.freeMemory()) / 1_048_576L;
            y = renderMetric(graphics, client, right, y, "CLIENT", client.getFps() + " FPS · " + usedMb + " Mo", TEXT);
        }
        if (enabled("coordinates", true)) {
            String coordinates = String.format(
                    Locale.ROOT,
                    "%.0f  %.0f  %.0f",
                    client.player.getX(), client.player.getY(), client.player.getZ()
            );
            y = renderMetric(graphics, client, right, y, "POSITION", coordinates, TEXT);
        }
        if (enabled("serverAddress", true)) {
            String address = client.getCurrentServer() == null ? "Monde local" : client.getCurrentServer().ip;
            renderMetric(graphics, client, right, y, "SERVEUR", address, GOLD);
        }
    }

    private static void renderKeys(GuiGraphicsExtractor graphics, Minecraft client) {
        int x = 10;
        int y = 10;
        if (enabled("keystrokes", true)) {
            key(graphics, client, x + 25, y, "W", client.options.keyUp.isDown(), 22, 20);
            key(graphics, client, x, y + 24, "A", client.options.keyLeft.isDown(), 22, 20);
            key(graphics, client, x + 25, y + 24, "S", client.options.keyDown.isDown(), 22, 20);
            key(graphics, client, x + 50, y + 24, "D", client.options.keyRight.isDown(), 22, 20);
            key(graphics, client, x, y + 48, "ESPACE", client.options.keyJump.isDown(), 72, 18);
            y += 70;
        }
        if (enabled("cps", true)) {
            panel(graphics, x, y, 72, 30);
            graphics.text(client.font, LEFT_CLICKS.size() + " CPS", x + 5, y + 5, TEXT, false);
            graphics.text(client.font, RIGHT_CLICKS.size() + " CPS", x + 39, y + 17, MUTED, false);
            graphics.text(client.font, "G", x + 5, y + 17, GOLD, false);
            graphics.text(client.font, "D", x + 30, y + 17, GREEN, false);
        }
    }

    private static void key(GuiGraphicsExtractor graphics, Minecraft client, int x, int y, String label, boolean down, int width, int height) {
        graphics.fill(x, y, x + width, y + height, down ? 0xE6F4B72B : PANEL);
        graphics.outline(x, y, width, height, down ? GOLD : BORDER);
        int color = down ? 0xFF090D0B : TEXT;
        int textX = x + Math.max(3, (width - client.font.width(label)) / 2);
        graphics.text(client.font, label, textX, y + 6, color, false);
    }

    private static int renderMetric(GuiGraphicsExtractor graphics, Minecraft client, int right, int y, String label, String value, int valueColor) {
        int width = Math.max(128, Math.max(client.font.width(label), client.font.width(value)) + 18);
        int x = right - width;
        panel(graphics, x, y, width, 34);
        graphics.text(client.font, label, x + 8, y + 5, MUTED, false);
        graphics.text(client.font, value, x + 8, y + 18, valueColor, false);
        return y + 40;
    }

    private static void renderMinimap(GuiGraphicsExtractor graphics, Minecraft client, int x, int y) {
        panel(graphics, x, y, 82, 82);
        for (int offset = 16; offset < 82; offset += 16) {
            graphics.verticalLine(x + offset, y + 5, y + 76, 0x44334238);
            graphics.horizontalLine(x + 5, x + 76, y + offset, 0x44334238);
        }
        Direction direction = client.player.getDirection();
        String heading = direction.getName().toUpperCase(Locale.ROOT);
        graphics.centeredText(client.font, "N", x + 41, y + 5, MUTED);
        graphics.centeredText(client.font, "◆", x + 41, y + 34, GOLD);
        graphics.centeredText(client.font, heading, x + 41, y + 65, TEXT);
    }

    private static void panel(GuiGraphicsExtractor graphics, int x, int y, int width, int height) {
        graphics.fill(x, y, x + width, y + height, PANEL);
        graphics.outline(x, y, width, height, BORDER);
    }
}
