package com.tiedup.remake.client.events;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.PoseType;
import com.tiedup.remake.v2.bondage.PoseTypeHelper;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

/**
 * Client-side handler for smooth leash proxy positioning.
 *
 * FIX: Changed from RenderLevelStageEvent.AFTER_ENTITIES to ClientTickEvent.
 * AFTER_ENTITIES positioned the proxy AFTER rendering, causing 1-frame lag.
 * ClientTickEvent positions BEFORE rendering for smooth leash display.
 *
 * Instead of waiting for server position updates (which causes lag),
 * this handler repositions the proxy entity locally each tick based
 * on the player's current position.
 */
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(
    modid = TiedUpMod.MOD_ID,
    value = Dist.CLIENT,
    bus = Mod.EventBusSubscriber.Bus.FORGE
)
public class LeashProxyClientHandler {

    /**
     * Map of player UUID -> proxy entity ID.
     * Uses UUID for player (persistent) and entity ID for proxy (runtime).
     */
    private static final Map<UUID, Integer> playerToProxy =
        new ConcurrentHashMap<>();

    /** Default Y offset for normal standing pose (neck height) */
    private static final double DEFAULT_Y_OFFSET = 1.3;

    /** Y offset for dogwalk pose (back/hip level) */
    private static final double DOGWALK_Y_OFFSET = 0.35;

    /**
     * Handle sync packet from server.
     * Called when a player gets leashed or unleashed.
     */
    public static void handleSyncPacket(
        UUID targetPlayerUUID,
        int proxyId,
        boolean attach
    ) {
        if (attach) {
            playerToProxy.put(targetPlayerUUID, proxyId);
            TiedUpMod.LOGGER.debug(
                "[LeashProxyClient] Registered proxy {} for player {}",
                proxyId,
                targetPlayerUUID
            );
        } else {
            playerToProxy.remove(targetPlayerUUID);
            TiedUpMod.LOGGER.debug(
                "[LeashProxyClient] Removed proxy for player {}",
                targetPlayerUUID
            );
        }
    }

    /**
     * FIX: Use ClientTickEvent instead of RenderLevelStageEvent.AFTER_ENTITIES.
     * This positions proxies BEFORE rendering, eliminating the 1-frame lag
     * that caused jittery leash rendering.
     */
    @SubscribeEvent
    public static void onClientTick(TickEvent.ClientTickEvent event) {
        // Only run at end of tick (after player position is updated)
        if (event.phase != TickEvent.Phase.END) {
            return;
        }

        if (playerToProxy.isEmpty()) {
            return;
        }

        Minecraft mc = Minecraft.getInstance();
        if (mc == null || mc.level == null || mc.isPaused()) {
            return;
        }
        Level level = mc.level;

        // Reposition each tracked proxy
        for (Map.Entry<UUID, Integer> entry : playerToProxy.entrySet()) {
            UUID playerUUID = entry.getKey();
            int proxyId = entry.getValue();

            Player playerEntity = level.getPlayerByUUID(playerUUID);
            Entity proxyEntity = level.getEntity(proxyId);

            if (playerEntity != null && proxyEntity != null) {
                // FIX: Calculate Y offset based on bind type (dogwalk vs normal)
                double yOffset = calculateYOffset(playerEntity);

                // Use current position (interpolation will be handled by renderer)
                double x = playerEntity.getX();
                double y = playerEntity.getY() + yOffset;
                double z = playerEntity.getZ() - 0.15;

                // Set proxy position
                proxyEntity.setPos(x, y, z);

                // Update old positions for smooth interpolation
                proxyEntity.xOld = proxyEntity.xo = x;
                proxyEntity.yOld = proxyEntity.yo = y;
                proxyEntity.zOld = proxyEntity.zo = z;
            }
        }
    }

    /**
     * Calculate Y offset based on player's bind type.
     * Dogwalk (DOGBINDER) uses lower offset for 4-legged pose.
     */
    private static double calculateYOffset(Player player) {
        IBondageState state = KidnappedHelper.getKidnappedState(player);
        if (state != null && state.isTiedUp()) {
            ItemStack bind = state.getEquipment(BodyRegionV2.ARMS);
            if (
                !bind.isEmpty() &&
                PoseTypeHelper.getPoseType(bind) == PoseType.DOG
            ) {
                return DOGWALK_Y_OFFSET;
            }
        }
        return DEFAULT_Y_OFFSET;
    }

    /**
     * Clear all tracked proxies.
     * Called when disconnecting from server.
     */
    public static void clearAll() {
        playerToProxy.clear();
    }
}
