package land.chipmunk.chipmunkmod.mixin;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.mojang.brigadier.CommandDispatcher;
import land.chipmunk.chipmunkmod.ChipmunkMod;
import land.chipmunk.chipmunkmod.command.CommandManager;
import land.chipmunk.chipmunkmod.listeners.Listener;
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
import land.chipmunk.chipmunkmod.modules.*;
import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.components.DebugScreenOverlay;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.contents.PlainTextContents;
import net.minecraft.network.chat.contents.TranslatableContents;
import net.minecraft.network.protocol.game.ClientboundCommandsPacket;
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
import net.minecraft.network.protocol.game.ClientboundSetTimePacket;
import net.minecraft.network.protocol.game.ClientboundSystemChatPacket;
import net.minecraft.world.flag.FeatureFlagSet;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(value = ClientPacketListener.class, priority = 1001)
public abstract class ClientPacketListenerMixin {
    @Final
    @Shadow
    private FeatureFlagSet enabledFeatures;
    @Final
    @Shadow
    private RegistryAccess.Frozen registryAccess;
    @Shadow
    private CommandDispatcher<SharedSuggestionProvider> commands;

    @Shadow
    public abstract ClientLevel getLevel ();

    @Inject(method = "handleLogin", at = @At("TAIL"))
    private void handleLogin (final ClientboundLoginPacket packet, final CallbackInfo ci) {
        final CommandBuildContext commandRegistryAccess = CommandBuildContext.simple(this.registryAccess, this.enabledFeatures);

        KaboomCheck.INSTANCE.onJoin();
        CommandManager.INSTANCE = new CommandManager(ChipmunkMod.CONFIG.commands.prefix, commandRegistryAccess);
        CommandCore.INSTANCE.init();
        SongPlayer.INSTANCE.coreReady();
        RainbowName.INSTANCE.init();
        ChomeNSBotCommandSuggestions.INSTANCE.init();
    }

    @Inject(method = "handleCommands", at = @At("TAIL"))
    private void handleCommands (final ClientboundCommandsPacket packet, final CallbackInfo ci) {
        KaboomCheck.INSTANCE.onCommandTree(this.commands);
    }

    @Inject(
            method = "handleSystemChat",
            at = @At(
                    value = "INVOKE",
                    target = "Lnet/minecraft/client/multiplayer/chat/ChatListener;handleSystemMessage(Lnet/minecraft/network/chat/Component;Z)V"
            ),
            cancellable = true
    )
    private void handleSystemChat (final ClientboundSystemChatPacket packet, final CallbackInfo ci) {
        final Component message = packet.content();

        if (
                (
                        RainbowName.INSTANCE.enabled &&
                                (
                                        message.getString().startsWith("Your nickname is now ") ||
                                                message.getString().startsWith("Nickname changed.")
                                )
                ) ||
                        (
                                message.getContents() instanceof final TranslatableContents translatableTextContent &&
                                        (
                                                translatableTextContent.getKey().equals("advMode.setCommand.success")
                                                        || translatableTextContent.getKey().equals("قيادة المجموعة: %s")
                                        )
                        )
        ) {
            ci.cancel();
            return;
        }

        for (final Listener listener : ListenerManager.listeners) {
            listener.chatMessageReceived(message);
        }

        if (
                message.getSiblings().size() > 1
                        && message.getSiblings().getFirst().getContents() instanceof final PlainTextContents textContent
                        && textContent.text().equals(ChomeNSBotCommandSuggestions.REQUEST_SUGGESTIONS_ID)
        ) ci.cancel();
    }

    @WrapOperation(
            method = "setActionBarText",
            at = @At(
                    value = "INVOKE",
                    target = "Lnet/minecraft/client/gui/Gui;setOverlayMessage(Lnet/minecraft/network/chat/Component;Z)V"
            )
    )
    private void setOverlayMessage (final Gui instance, final Component message, final boolean animate, final Operation<Void> original) {
        for (final Listener listener : ListenerManager.listeners) {
            listener.overlayMessageReceived(message);
        }

        original.call(instance, message, animate);

        // checking for the ChomeNS Bot selector message doesn't really
        // do much here since the message is just an empty string
        // that gets sent only when you join (or the bot restarts),
        // so I do not ignore them
    }

    @Inject(method = "sendChat", at = @At("HEAD"), cancellable = true)
    private void sendChat (final String content, final CallbackInfo ci) {
        if (Chat.NEXT_CHAT_PLAYER.get()) {
            Chat.NEXT_CHAT_PLAYER.set(false);
            return;
        }

        CustomChat.INSTANCE.chat(content);
        ci.cancel();
    }

    @Inject(method = "handleSetTime", at = @At("TAIL"))
    private void handleSetTime (final ClientboundSetTimePacket packet, final CallbackInfo ci) {
        for (final Listener listener : ListenerManager.listeners) listener.timeUpdate();
    }

    @WrapOperation(
            method = "tick",
            at = @At(
                    value = "INVOKE",
                    target = "Lnet/minecraft/client/gui/components/DebugScreenOverlay;showNetworkCharts()Z"
            )
    )
    private boolean showNetworkCharts (final DebugScreenOverlay instance, final Operation<Boolean> original) {
        return true;
    }
}
