package com.tiedup.remake.network.cell;

import com.tiedup.remake.cells.CellDataV2;
import com.tiedup.remake.cells.CellRegistryV2;
import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.network.PacketRateLimiter;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.network.sync.SyncManager;
import com.tiedup.remake.personality.PersonalityState;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.UUID;
import java.util.function.Supplier;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;

/**
 * Packet to assign (or clear) a cell on a collar.
 * Client -> Server
 */
public class PacketAssignCellToCollar {

    private final UUID targetEntityUUID; // The entity wearing the collar
    private final UUID cellId; // The cell to assign (null = clear)

    public PacketAssignCellToCollar(UUID targetEntityUUID, UUID cellId) {
        this.targetEntityUUID = targetEntityUUID;
        this.cellId = cellId;
    }

    public static void encode(
        PacketAssignCellToCollar msg,
        FriendlyByteBuf buf
    ) {
        buf.writeUUID(msg.targetEntityUUID);
        buf.writeBoolean(msg.cellId != null);
        if (msg.cellId != null) {
            buf.writeUUID(msg.cellId);
        }
    }

    public static PacketAssignCellToCollar decode(FriendlyByteBuf buf) {
        UUID targetEntityUUID = buf.readUUID();
        UUID cellId = buf.readBoolean() ? buf.readUUID() : null;
        return new PacketAssignCellToCollar(targetEntityUUID, cellId);
    }

    public static void handle(
        PacketAssignCellToCollar msg,
        Supplier<NetworkEvent.Context> ctx
    ) {
        ctx
            .get()
            .enqueueWork(() -> {
                ServerPlayer sender = ctx.get().getSender();
                if (sender == null) return;

                // MEDIUM FIX: Rate limiting to prevent cell assignment spam
                if (!PacketRateLimiter.allowPacket(sender, "action")) {
                    return;
                }

                // Find target entity
                LivingEntity target = findEntity(sender, msg.targetEntityUUID);
                if (target == null) {
                    TiedUpMod.LOGGER.debug(
                        "[PacketAssignCellToCollar] Target not found: {}",
                        msg.targetEntityUUID
                    );
                    return;
                }

                // Check distance (max 10 blocks)
                if (sender.distanceTo(target) > 10.0) {
                    TiedUpMod.LOGGER.debug(
                        "[PacketAssignCellToCollar] Target too far"
                    );
                    return;
                }

                // Get target's kidnapped state
                IBondageState state = KidnappedHelper.getKidnappedState(target);
                if (state == null || !state.hasCollar()) {
                    TiedUpMod.LOGGER.debug(
                        "[PacketAssignCellToCollar] Target has no collar"
                    );
                    return;
                }

                ItemStack collarStack = state.getEquipment(BodyRegionV2.NECK);
                if (!CollarHelper.isCollar(collarStack)) {
                    TiedUpMod.LOGGER.debug(
                        "[PacketAssignCellToCollar] Invalid collar item"
                    );
                    return;
                }

                // Security: Verify sender owns the collar (or is admin)
                if (
                    !CollarHelper.isOwner(collarStack, sender) &&
                    !sender.hasPermissions(2)
                ) {
                    TiedUpMod.LOGGER.debug(
                        "[PacketAssignCellToCollar] Sender is not collar owner"
                    );
                    return;
                }

                // If assigning a cell, verify ownership
                CellDataV2 cell = null;
                if (msg.cellId != null) {
                    CellRegistryV2 registry = CellRegistryV2.get(
                        sender.serverLevel()
                    );
                    cell = registry.getCell(msg.cellId);
                    if (cell == null) {
                        TiedUpMod.LOGGER.debug(
                            "[PacketAssignCellToCollar] Cell not found"
                        );
                        return;
                    }
                    if (
                        !cell.isOwnedBy(sender.getUUID()) &&
                        !sender.hasPermissions(2)
                    ) {
                        TiedUpMod.LOGGER.debug(
                            "[PacketAssignCellToCollar] Sender doesn't own the cell"
                        );
                        return;
                    }
                }

                // Set the cell ID on the collar
                if (msg.cellId != null) {
                    CollarHelper.setCellId(collarStack, msg.cellId);
                } else {
                    // Clear cell assignment
                    CompoundTag collarTag = collarStack.getTag();
                    if (collarTag != null) {
                        collarTag.remove("cellId");
                    }
                }

                // Sync PersonalityState for damsels
                if (target instanceof EntityDamsel damsel) {
                    PersonalityState pState = damsel.getPersonalityState();
                    if (pState != null) {
                        if (msg.cellId != null && cell != null) {
                            pState.assignCell(
                                msg.cellId,
                                cell,
                                damsel.getUUID()
                            );
                        } else {
                            pState.unassignCell();
                        }
                    }
                }

                // Sync changes
                if (target instanceof ServerPlayer targetPlayer) {
                    SyncManager.syncAll(targetPlayer);
                }

                // Send feedback
                if (msg.cellId != null) {
                    String cellName =
                        cell != null && cell.getName() != null
                            ? cell.getName()
                            : msg.cellId.toString().substring(0, 8);

                    SystemMessageManager.sendToPlayer(
                        sender,
                        SystemMessageManager.MessageCategory.INFO,
                        "Cell '" + cellName + "' assigned to collar"
                    );
                } else {
                    SystemMessageManager.sendToPlayer(
                        sender,
                        SystemMessageManager.MessageCategory.INFO,
                        "Cell cleared from collar"
                    );
                }

                TiedUpMod.LOGGER.info(
                    "[PacketAssignCellToCollar] {} {} cell on {}'s collar",
                    sender.getName().getString(),
                    msg.cellId != null ? "assigned" : "cleared",
                    target.getName().getString()
                );
            });

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

    private static LivingEntity findEntity(ServerPlayer sender, UUID entityId) {
        // Try player first
        Player player = sender.level().getPlayerByUUID(entityId);
        if (player != null) return player;

        // Search nearby entities
        var searchBox = sender.getBoundingBox().inflate(64);
        for (LivingEntity entity : sender
            .level()
            .getEntitiesOfClass(LivingEntity.class, searchBox)) {
            if (entity.getUUID().equals(entityId)) {
                return entity;
            }
        }
        return null;
    }
}
