package land.chipmunk.chipmunkmod.modules.custom_chat;

import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.modules.Chat;
import land.chipmunk.chipmunkmod.modules.CommandCore;
import land.chipmunk.chipmunkmod.modules.KaboomCheck;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.StringUtil;
import java.util.Map;
import java.util.regex.Pattern;

public class CustomChat {
    public static final CustomChat INSTANCE = new CustomChat(Minecraft.getInstance());

    private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson();
    private static final CustomChatComponentRenderer RENDERER = new CustomChatComponentRenderer();
    private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer

            // https://sus.red/abc?a=b&c=d will still break the click events, though
            .legacyAmpersand()

            .toBuilder()

            .extractUrls(
                    Pattern
                            .compile("((https?://(ww(w|\\d)\\.)?|ww(w|\\d))[-a-zA-Z0-9@:%._+~#=]{1,256}"
                                             + "\\.[a-zA-Z0-9]{1,63}\\b([-a-zA-Z0-9@:%_+.~#?&/=]*))"),
                    Style.style(
                            NamedTextColor.BLUE,
                            TextDecoration.UNDERLINED,
                            HoverEvent.showText(
                                    Component
                                            .text("Click here to open the URL")
                                            .color(NamedTextColor.BLUE)
                            )
                    )
            )

            // > `this.useTerriblyStupidHexFormat = true`
            // i know it is stupid indeed,
            // but i also want the compatibility to the kaboom chat
            .useUnusualXRepeatedCharacterHexFormat() // &x&1&2&3&4&5&6abc

            .build();

    public static final ThreadLocal<Boolean> SHOULD_IGNORE_INVALID_CHAR = ThreadLocal.withInitial(() -> true);

    private final Minecraft client;

    public boolean enabled;
    public boolean onlyUseWhenNecessary;

    public Component format;

    public CustomChat (final Minecraft client) {
        this.client = client;
        reloadFromConfig();
    }

    public void reloadFromConfig () {
        this.format = ChipmunkMod.CONFIG.customChat.format;
        this.enabled = ChipmunkMod.CONFIG.customChat.enabled;
        this.onlyUseWhenNecessary = ChipmunkMod.CONFIG.customChat.onlyUseWhenNecessary;
    }

    public void chat (final String message) {
        final LocalPlayer player = client.player;
        if (player == null) return;
        if (shouldUsePlayerChat(player, message)) {
            Chat.sendChatMessage(message, true);
            return;
        }

        final Component styledMessage = SERIALIZER.deserialize(message);

        final String username = Minecraft.getInstance().getUser().getName();

        final CustomChatContext context = new CustomChatContext(player.getStringUUID(), styledMessage,
                                                                Map.of("MESSAGE", message, "USERNAME", username));
        final Component renderedFormat = RENDERER.render(format, context)
                .compact();
        final String json = GSON.serialize(renderedFormat);

        CommandCore.INSTANCE.run((KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw @a " : "tellraw @a ") + json);
    }

    private boolean shouldUsePlayerChat (final LocalPlayer player, final String message) {
        return !enabled || isUnnecessary(message) || !player.canUseGameMasterBlocks();
    }

    private boolean isUnnecessary (final String message) {
        if (!onlyUseWhenNecessary || message.isEmpty() || message.length() > 256) return false;

        for (final char character : message.toCharArray()) {
            SHOULD_IGNORE_INVALID_CHAR.set(false);
            if (!StringUtil.isAllowedChatCharacter(character)) return false;
        }

        return true;
    }
}
