package com.r3944realms.leashedplayer;

import com.r3944realms.leashedplayer.client.renders.entities.*;
import com.r3944realms.leashedplayer.content.ModKeyMapping;
import com.r3944realms.leashedplayer.content.commands.Command;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry;
import com.r3944realms.leashedplayer.content.gamerules.Server.OpenTOPNeededModeWhenScreenIsNotNull;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.content.items.type.ILeashRopeArrow;
import com.r3944realms.leashedplayer.content.items.type.INestleRopeArrow;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import com.r3944realms.leashedplayer.network.server.Code;
import com.r3944realms.leashedplayer.network.server.DecreaseLeashRopeLength;
import com.r3944realms.leashedplayer.network.server.IncreaseLeashRopeLength;
import com.r3944realms.leashedplayer.utils.Util;
import mcjty.theoneprobe.config.Config;
import mcjty.theoneprobe.gui.GuiNote;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.ChatScreen;
import net.minecraft.client.gui.screens.DisconnectedScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.client.resources.PlayerSkin;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.DisconnectionDetails;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FastColor;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.item.component.ChargedProjectiles;
import net.minecraft.world.phys.HitResult;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModList;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.*;
import net.neoforged.neoforge.network.PacketDistributor;

import java.util.List;


public abstract class ClientEventHandler {
    public static final String ADDICTION = "multiplayer.disconnect.addiction";
    @EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.GAME, modid = LeashedPlayer.MOD_ID)
    public static class Game extends ClientEventHandler {
        private static int oldSelect;
        private static boolean configSaved = false;
        private static final boolean IS_TOP_LOADED = ModList.get().isLoaded("theoneprobe");
        @SubscribeEvent
        public static void onClientTick(ClientTickEvent.Pre event) {
            Minecraft mc = Minecraft.getInstance();
            if (mc.level == null) return;
            if (GameruleRegistry.getGameruleBoolValue(mc.level, OpenTOPNeededModeWhenScreenIsNotNull.ID)){
                Screen currentScreen = mc.screen;
                if (IS_TOP_LOADED) {
                    if (currentScreen != null) {
                        if (currentScreen instanceof GuiNote || currentScreen instanceof ChatScreen) {
                            configSaved = false;
                            oldSelect = Config.needsProbe.get();
                        } else {
                            if (!configSaved) {
                                oldSelect = Config.needsProbe.get();
                                Config.setProbeNeeded(Config.PROBE_NEEDED);
                                configSaved = true;
                            } else {
                                Config.setProbeNeeded(Config.PROBE_NEEDED);
                            }
                        }
                    } else {
                        Config.setProbeNeeded(oldSelect);
                        configSaved = false;
                    }
                }
            }
        }
        @SubscribeEvent
        public static void onScreenOpen(ScreenEvent.Opening opening) {
            if(opening.getNewScreen() instanceof DisconnectedScreen screen) {
                if (screen.details.reason().getString().equals("You are already connected to this proxy!")) {
                    screen.details = new DisconnectionDetails(Component.translatable(ADDICTION).withStyle(ChatFormatting.RED));
                }
            }
        }
        @SubscribeEvent
        public static void onKetBoardInput(InputEvent.Key event) {
            Minecraft minecraft = Minecraft.getInstance();
            LocalPlayer player = minecraft.player;
            assert player != null;
            if (ModKeyMapping.KEY_APPLY_TALKAREA_PREFERENCE.isDown()) {
                String prefix =  (Command.SHOULD_USE_PREFIX ? Command.PREFIX : "") + " ";
                player.connection.sendCommand(prefix + "talkArea usePreference");
            }
            if (ModKeyMapping.KEY_ADD_LEASH_LENGTH.isDown()) {
                PlayerLeashable playerLeashable = (PlayerLeashable) player;
                if (playerLeashable.getLeashDataFromEntityData() == null) {
                    assert minecraft.level != null;
                    List<HitResult> refLookAtEntityHitResult = Util.getRefLookAtEntityHitResult(player, minecraft.level, 32, entity -> entity instanceof LivingEntity);
                    Entity theNearestEntityFromHitResultList = Util.getTheNearestEntityFromHitResultList(player, refLookAtEntityHitResult);
                    if(theNearestEntityFromHitResultList != null) {
                        if (theNearestEntityFromHitResultList instanceof Player refPlayer) {
                            PacketDistributor.sendToServer(new IncreaseLeashRopeLength(Code.OTHER_ST, refPlayer.getStringUUID()));
                        }
                    }
                }
                if (playerLeashable.getLeashDataFromEntityData() != null) {
                    PacketDistributor.sendToServer(new IncreaseLeashRopeLength(Code.SELF, player.getStringUUID()));
                }
            }
            if (ModKeyMapping.KEY_SUB_LEASH_LENGTH.isDown()) {
                PlayerLeashable playerLeashable = (PlayerLeashable) player;
                if (playerLeashable.getLeashDataFromEntityData() == null) {
                    assert minecraft.level != null;
                    List<HitResult> refLookAtEntityHitResult = Util.getRefLookAtEntityHitResult(player, minecraft.level, 32, entity -> entity instanceof LivingEntity);
                    Entity theNearestEntityFromHitResultList = Util.getTheNearestEntityFromHitResultList(player, refLookAtEntityHitResult);
                    if(theNearestEntityFromHitResultList != null) {
                        if (theNearestEntityFromHitResultList instanceof Player refPlayer) {
                            PacketDistributor.sendToServer(new DecreaseLeashRopeLength(Code.OTHER_ST, refPlayer.getStringUUID()));
                        }
                    }
                }
                if (playerLeashable.getLeashDataFromEntityData() != null) {
                    PacketDistributor.sendToServer(new DecreaseLeashRopeLength(Code.SELF, player.getStringUUID()));
                }
            }
        }
    }

    @EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD, modid = LeashedPlayer.MOD_ID)
    public static class Mod extends ClientEventHandler {
        @SubscribeEvent
        public static void onRegisterItemProperties (FMLClientSetupEvent event){
            event.enqueueWork(() -> {
                ItemProperties.register(Items.CROSSBOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow"),
                        ((pStack, pLevel, pEntity, pSeed) -> {
                            ChargedProjectiles chargedProjectiles = pStack.get(DataComponents.CHARGED_PROJECTILES);
                            return chargedProjectiles != null && (chargedProjectiles.contains(ModItemRegister.LEASH_ROPE_ARROW.get()) || chargedProjectiles.contains(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get())) ? 1.0F : 0.0F;}
                ));
                ItemProperties.register(Items.CROSSBOW, ResourceLocation.withDefaultNamespace("nestle_rope_arrow"),
                    ((pStack, pLevel, pEntity, pSeed) -> {
                            ChargedProjectiles chargedProjectiles = pStack.get(DataComponents.CHARGED_PROJECTILES);
                            return chargedProjectiles != null && (chargedProjectiles.contains(ModItemRegister.NESTLE_ROPE_ARROW.get())) ? 1.0F : 0.0F;}
                ));
                ItemProperties.register(Items.BOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow_pulling"),
                        ((pStack, pLevel, pEntity, pSeed) ->
                                (pEntity != null && pEntity.isUsingItem() && pEntity.getUseItem() == pStack && ILeashRopeArrow.isLeashRopeArrow(pStack, pEntity)) ? 1.0F : 0.0F
                ));
                ItemProperties.register(Items.BOW, ResourceLocation.withDefaultNamespace("nestle_rope_arrow_pulling"),
                        ((pStack, pLevel, pEntity, pSeed) ->
                                (pEntity != null && pEntity.isUsingItem() && pEntity.getUseItem() == pStack && INestleRopeArrow.isNestleRopeArrow(pStack, pEntity)) ? 1.0F : 0.0F
                ));
            });

        }

        @SubscribeEvent
        public static void registerKeyMapping(RegisterKeyMappingsEvent event) {
            event.register(ModKeyMapping.KEY_APPLY_TALKAREA_PREFERENCE);
            event.register(ModKeyMapping.KEY_ADD_LEASH_LENGTH);
            event.register(ModKeyMapping.KEY_SUB_LEASH_LENGTH);
        }

        @SubscribeEvent
        public static void onRegisterRenderer (EntityRenderersEvent.RegisterRenderers event) {
            event.registerEntityRenderer(ModEntityRegister.NESTLE_ROPE_ARROW.get(), NestleRopeArrowRenderer::new);
            event.registerEntityRenderer(ModEntityRegister.LEASH_ROPE_ARROW.get(), LeashRopeArrowRenderer::new);
            event.registerEntityRenderer(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), SpectralLeashRopeArrowRenderer::new);
            event.registerEntityRenderer(ModEntityRegister.KID.get(), KidPlayerRenderer::create);
        }

        @SubscribeEvent
        public static void onAddLayers (EntityRenderersEvent.AddLayers event){

            PlayerRenderer renderer = event.getSkin(PlayerSkin.Model.WIDE);
            if (renderer instanceof PlayerRenderer playerRenderer) {
                playerRenderer.addLayer(new ChestItemLayerRenderer<>(playerRenderer, event.getContext().getItemInHandRenderer()));
            }

            PlayerRenderer slimRenderer = event.getSkin(PlayerSkin.Model.SLIM);
            if (slimRenderer instanceof PlayerRenderer slimPlayerRenderer) {
                slimPlayerRenderer.addLayer(new ChestItemLayerRenderer<>(slimPlayerRenderer, event.getContext().getItemInHandRenderer()));
            }
        }

        @SubscribeEvent
        public static void onRegisterItemColorHandlers (RegisterColorHandlersEvent.Item event){
            event.register(
                    (color, i) -> i > 0
                            ? -1
                            : FastColor.ARGB32.opaque(color.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).getColor()),
                    ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get()
            );
        }

    }
}
