package com.tiedup.remake.network.item;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.AdjustmentHelper;
import com.tiedup.remake.network.sync.SyncManager;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.function.Supplier;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;

/**
 *
 * Sent by client when player adjusts a gag or blindfold position.
 * Server validates and applies the adjustment, then syncs to all clients.
 */
public class PacketAdjustItem {

    private final BodyRegionV2 region;
    private final float adjustmentValue;
    private final float scaleValue;

    /**
     * Create adjustment packet.
     *
     * @param region The body region (MOUTH or EYES)
     * @param adjustmentValue The adjustment value (-4.0 to +4.0)
     * @param scaleValue The scale value (0.5 to 2.0)
     */
    public PacketAdjustItem(
        BodyRegionV2 region,
        float adjustmentValue,
        float scaleValue
    ) {
        this.region = region;
        this.adjustmentValue = adjustmentValue;
        this.scaleValue = scaleValue;
    }

    /**
     * Encode the packet to the network buffer.
     *
     * @param buf The buffer to write to
     */
    public void encode(FriendlyByteBuf buf) {
        buf.writeEnum(region);
        buf.writeFloat(adjustmentValue);
        buf.writeFloat(scaleValue);
    }

    /**
     * Decode the packet from the network buffer.
     *
     * @param buf The buffer to read from
     * @return The decoded packet
     */
    public static PacketAdjustItem decode(FriendlyByteBuf buf) {
        BodyRegionV2 region = buf.readEnum(BodyRegionV2.class);
        float value = buf.readFloat();
        float scale = buf.readFloat();
        return new PacketAdjustItem(region, value, scale);
    }

    /**
     * Handle the packet on the receiving side (SERVER SIDE).
     *
     * @param ctx The network context
     */
    public void handle(Supplier<NetworkEvent.Context> ctx) {
        ctx
            .get()
            .enqueueWork(() -> {
                ServerPlayer player = ctx.get().getSender();
                if (player == null) {
                    return;
                }

                // Rate limiting: Prevent adjustment spam
                if (
                    !com.tiedup.remake.network.PacketRateLimiter.allowPacket(
                        player,
                        "action"
                    )
                ) {
                    return;
                }

                handleServer(player);
            });
        ctx.get().setPacketHandled(true);
    }

    /**
     * Handle the packet on the server side.
     * Validates the adjustment and applies it to the player's item.
     *
     * @param player The player who sent the packet
     */
    private void handleServer(ServerPlayer player) {
        PlayerBindState state = PlayerBindState.getInstance(player);
        if (state == null) {
            TiedUpMod.LOGGER.warn(
                "[PACKET] PacketAdjustItem received but PlayerBindState is null for {}",
                player.getName().getString()
            );
            return;
        }

        // SECURITY: Validate adjustment value (prevent NaN, Infinity, out-of-bounds)
        if (
            Float.isNaN(adjustmentValue) ||
            Float.isInfinite(adjustmentValue) ||
            Float.isNaN(scaleValue) ||
            Float.isInfinite(scaleValue)
        ) {
            TiedUpMod.LOGGER.warn(
                "SECURITY: Invalid adjustment value from {}: adj={}, scale={}",
                player.getName().getString(),
                adjustmentValue,
                scaleValue
            );
            return;
        }

        // Valid range check (-5.0 to +5.0 pixels, with margin)
        if (adjustmentValue < -5.0f || adjustmentValue > 5.0f) {
            TiedUpMod.LOGGER.debug(
                "[PACKET] Adjustment value out of bounds from {}: {}",
                player.getName().getString(),
                adjustmentValue
            );
            return;
        }

        // Get the item to adjust
        ItemStack stack = switch (region) {
            case MOUTH -> state.getEquipment(BodyRegionV2.MOUTH);
            case EYES -> state.getEquipment(BodyRegionV2.EYES);
            default -> ItemStack.EMPTY;
        };

        // Validate
        if (stack.isEmpty()) {
            TiedUpMod.LOGGER.debug(
                "[PACKET] PacketAdjustItem: No {} equipped for {}",
                region,
                player.getName().getString()
            );
            return;
        }

        if (!AdjustmentHelper.isAdjustable(stack)) {
            TiedUpMod.LOGGER.warn(
                "[PACKET] PacketAdjustItem: Item {} is not adjustable",
                stack.getItem()
            );
            return;
        }

        // Apply adjustment (AdjustmentHelper clamps the value)
        AdjustmentHelper.setAdjustment(stack, adjustmentValue);
        AdjustmentHelper.setScale(stack, scaleValue);

        TiedUpMod.LOGGER.debug(
            "[PACKET] Applied adjustment {} scale {} to {} for {}",
            adjustmentValue,
            scaleValue,
            region,
            player.getName().getString()
        );

        // Sync inventory to all tracking players
        SyncManager.syncInventory(player);
    }
}
