package land.chipmunk.chipmunkmod.modules;

import com.mojang.authlib.GameProfile;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.util.ColorUtilities;
import land.chipmunk.chipmunkmod.util.RandomUtilities;
import land.chipmunk.chipmunkmod.util.UUIDUtilities;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class RainbowName {
    public static final RainbowName INSTANCE = new RainbowName(Minecraft.getInstance());
    private final Minecraft client;
    private final Random random = new Random();

    public boolean enabled = false;
    public String displayName;
    private Timer timer = null;
    private String team;
    private int startHue = 0;

    public RainbowName (final Minecraft client) {
        this.client = client;
        this.displayName = client.getUser().getName();
    }

    public void init () {
        final TimerTask task = new TimerTask() {
            public void run () {
                tick();
            }
        };

        if (timer != null) cleanup();

        timer = new Timer();
        timer.schedule(task, 0, 50);
    }

    public void enable () {
        final ClientPacketListener networkHandler = client.getConnection();
        if (networkHandler == null) return;
        final GameProfile profile = networkHandler.getLocalGameProfile();

        final String username = RandomUtilities.emptyUsername(random);
        team = RandomUtilities.randomString(random, RandomUtilities.TEAM_ALLOWED_CHARS, 16);
        final String selfSelector = UUIDUtilities.selector(profile.id());

        networkHandler.sendCommand("extras:username " + username);
        CommandCore.INSTANCE.run("minecraft:team add " + team);
        CommandCore.INSTANCE.run("minecraft:team join " + team + " " + selfSelector);

        enabled = true;
    }

    public void disable () {
        final ClientPacketListener networkHandler = client.getConnection();
        if (networkHandler == null) {
            enabled = false;
            return;
        }
        final GameProfile profile = networkHandler.getLocalGameProfile();

        CommandCore.INSTANCE.run("essentials:nick " + profile.id() + " off");
        CommandCore.INSTANCE.run("minecraft:team remove " + team);
        networkHandler.sendCommand("extras:username " + profile.name());
        enabled = false;
    }

    private void tick () {
        try {
            final ClientPacketListener networkHandler = client.getConnection();

            if (networkHandler == null) {
                cleanup();
                return;
            }

            if (!enabled) return;

            final GameProfile profile = networkHandler.getLocalGameProfile();
            int hue = startHue;
            final int increment = (int) (360.0 / Math.max(displayName.length(), 20));

            Component component = Component.empty();
            final StringBuilder essentialsNickname = new StringBuilder();

            for (final char character : displayName.toCharArray()) {
                final String color = String.format("%06x", ColorUtilities.hsvToRgb(hue, 100, 100));
                component = component.append(Component.text(character).color(TextColor.fromHexString("#" + color)));
                essentialsNickname.append("&#").append(color).append(character != ' ' ? character : '_');
                hue = (hue + increment) % 360;
            }

            CommandCore.INSTANCE.run("minecraft:team modify " + team + " prefix " + GsonComponentSerializer.gson().serialize(component));
            CommandCore.INSTANCE.run("essentials:nick " + profile.id() + " " + essentialsNickname);

            startHue = (startHue + increment) % 360;
        } catch (final Exception e) {
            ChipmunkMod.LOGGER.error("Error while ticking rainbow name", e);
        }
    }

    public void cleanup () {
        if (timer == null) return;

        timer.cancel();
        timer.purge();
        timer = null;
    }
}
