package com.tiedup.remake.client.animation.render;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.state.PlayerBindState;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

/**
 * Hides held items when player has arms bound or is wearing mittens.
 *
 * <p>Uses Pre/Post pattern to temporarily replace held items with empty
 * stacks for rendering, then restore them after.
 *
 * <p>Extracted from PlayerArmHideEventHandler for single-responsibility.
 */
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
    modid = TiedUpMod.MOD_ID,
    bus = Mod.EventBusSubscriber.Bus.FORGE,
    value = Dist.CLIENT
)
public class HeldItemHideHandler {

    /**
     * Stored items to restore after rendering.
     * Key: Player entity ID (int), Value: [mainHand, offHand]
     */
    private static final Int2ObjectMap<ItemStack[]> storedItems =
        new Int2ObjectOpenHashMap<>();

    // LOW priority + isCanceled guard: skip mutation when any earlier-
    // priority canceller fired. Paired Post uses receiveCanceled = true
    // and the storedItems map as a sentinel so held items still get
    // restored even when Forge would otherwise skip Post on a cancelled
    // Pre.
    @SubscribeEvent(priority = EventPriority.LOW)
    public static void onRenderPlayerPre(RenderPlayerEvent.Pre event) {
        if (event.isCanceled()) {
            return;
        }

        Player player = event.getEntity();
        if (!(player instanceof AbstractClientPlayer)) {
            return;
        }

        if (player.isRemoved() || !player.isAlive()) {
            return;
        }

        PlayerBindState state = PlayerBindState.getInstance(player);
        if (state == null) {
            return;
        }

        boolean hasArmsBound = state.hasArmsBound();
        boolean hasMittens = state.hasMittens();

        if (hasArmsBound || hasMittens) {
            ItemStack mainHand = player.getItemInHand(
                InteractionHand.MAIN_HAND
            );
            ItemStack offHand = player.getItemInHand(InteractionHand.OFF_HAND);

            if (!mainHand.isEmpty() || !offHand.isEmpty()) {
                storedItems.put(
                    player.getId(),
                    new ItemStack[] { mainHand.copy(), offHand.copy() }
                );

                player.setItemInHand(
                    InteractionHand.MAIN_HAND,
                    ItemStack.EMPTY
                );
                player.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY);
            }
        }
    }

    @SubscribeEvent(receiveCanceled = true)
    public static void onRenderPlayerPost(RenderPlayerEvent.Post event) {
        Player player = event.getEntity();
        if (!(player instanceof AbstractClientPlayer)) {
            return;
        }

        ItemStack[] items = storedItems.remove(player.getId());
        if (items != null) {
            player.setItemInHand(InteractionHand.MAIN_HAND, items[0]);
            player.setItemInHand(InteractionHand.OFF_HAND, items[1]);
        }
    }

    /** Drop tracked state for an entity leaving the level. */
    public static void onEntityLeave(int entityId) {
        storedItems.remove(entityId);
    }

    /** Drop all tracked state; called on world unload. */
    public static void clearAll() {
        storedItems.clear();
    }
}
