package com.tiedup.remake.v2.bondage.network;

import com.tiedup.remake.network.PacketRateLimiter;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.IV2BondageItem;
import com.tiedup.remake.v2.bondage.V2EquipResult;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenItemRegistry;
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;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * Client→Server: Player equips a bondage item from their own inventory onto a body region.
 */
public class PacketV2SelfEquip {

    private static final Logger LOGGER = LogManager.getLogger(
        "PacketV2SelfEquip"
    );

    private final BodyRegionV2 region;
    private final int inventorySlot;

    public PacketV2SelfEquip(BodyRegionV2 region, int inventorySlot) {
        this.region = region;
        this.inventorySlot = inventorySlot;
    }

    public static void encode(PacketV2SelfEquip msg, FriendlyByteBuf buf) {
        buf.writeEnum(msg.region);
        buf.writeVarInt(msg.inventorySlot);
    }

    public static PacketV2SelfEquip decode(FriendlyByteBuf buf) {
        return new PacketV2SelfEquip(
            buf.readEnum(BodyRegionV2.class),
            buf.readVarInt()
        );
    }

    public static void handle(
        PacketV2SelfEquip msg,
        Supplier<NetworkEvent.Context> ctxSupplier
    ) {
        NetworkEvent.Context ctx = ctxSupplier.get();
        ctx.enqueueWork(() -> {
            ServerPlayer player = ctx.getSender();
            if (player == null) return;
            if (!PacketRateLimiter.allowPacket(player, "action")) return;

            // Validate slot index
            if (
                msg.inventorySlot < 0 ||
                msg.inventorySlot >= player.getInventory().getContainerSize()
            ) return;

            ItemStack stack = player.getInventory().getItem(msg.inventorySlot);
            if (stack.isEmpty()) return;
            if (
                !(stack.getItem() instanceof IV2BondageItem bondageItem)
            ) return;

            // Warn if data-driven item has no definition (missing JSON or reload issue)
            if (
                bondageItem instanceof DataDrivenBondageItem &&
                DataDrivenItemRegistry.get(stack) == null
            ) {
                LOGGER.warn(
                    "[V2SelfEquip] Data-driven item in slot {} has no definition — equip blocked. Stack NBT: {}",
                    msg.inventorySlot,
                    stack.getTag()
                );
                return;
            }

            // Validate item targets this region
            if (
                !bondageItem.getOccupiedRegions(stack).contains(msg.region)
            ) return;

            // Furniture seat blocks this region
            if (
                player.isPassenger() &&
                player.getVehicle() instanceof
                    com.tiedup.remake.v2.furniture.ISeatProvider provider
            ) {
                com.tiedup.remake.v2.furniture.SeatDefinition seat =
                    provider.getSeatForPassenger(player);
                if (
                    seat != null && seat.blockedRegions().contains(msg.region)
                ) {
                    return; // Region blocked by furniture
                }
            }

            // Try equip (handles conflict resolution)
            V2EquipResult result = V2EquipmentHelper.equipItem(player, stack);
            if (result.isSuccess()) {
                // Remove from inventory (or reduce count)
                player.getInventory().removeItem(msg.inventorySlot, 1);
                // Return any displaced items to inventory
                if (result.displaced() != null) {
                    for (ItemStack displaced : result.displaced()) {
                        if (!displaced.isEmpty()) {
                            player
                                .getInventory()
                                .placeItemBackInInventory(displaced);
                        }
                    }
                }
            }
        });
        ctx.setPacketHandled(true);
    }
}
