package com.tiedup.remake.network.sync;

import com.tiedup.remake.network.base.AbstractPlayerSyncPacket;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.state.ICaptor;
import com.tiedup.remake.util.KidnappedHelper;
import java.util.UUID;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

/**
 * Packet to synchronize enslavement state between server and client.
 * Sent when a player is enslaved, freed, or transfers masters.
 *
 * Direction: Server → Client (S2C)
 */
public class PacketSyncEnslavement extends AbstractPlayerSyncPacket {

    private final UUID masterUUID; // The master's UUID (null if free)
    private final UUID transportUUID; // The transport entity's UUID (null if no transport)
    private final boolean isEnslaved; // Quick flag for state check

    /**
     * Create a packet to sync a player's enslavement state.
     *
     * @param targetUUID The slave player's UUID
     * @param masterUUID The master's UUID, or null if not enslaved
     * @param transportUUID The transport entity's UUID, or null if no transport
     * @param isEnslaved Whether the player is currently enslaved
     */
    public PacketSyncEnslavement(
        UUID targetUUID,
        UUID masterUUID,
        UUID transportUUID,
        boolean isEnslaved
    ) {
        super(targetUUID);
        this.masterUUID = masterUUID;
        this.transportUUID = transportUUID;
        this.isEnslaved = isEnslaved;
    }

    /**
     * Create a packet from a player's current enslavement state.
     *
     * @param player The player
     * @return The packet, or null if player has no kidnapped state
     */
    public static PacketSyncEnslavement fromPlayer(Player player) {
        IBondageState state = KidnappedHelper.getKidnappedState(player);
        if (state == null) {
            return null;
        }

        UUID captorUUID = null;
        UUID proxyUUID = null;
        boolean isCaptured = state.isCaptive();

        if (isCaptured) {
            ICaptor captor = state.getCaptor();
            if (captor != null && captor.getEntity() != null) {
                captorUUID = captor.getEntity().getUUID();
            }

            Entity proxy = state.getTransport();
            if (proxy != null) {
                proxyUUID = proxy.getUUID();
            }
        }

        return new PacketSyncEnslavement(
            player.getUUID(),
            captorUUID,
            proxyUUID,
            isCaptured
        );
    }

    /**
     * Encode the packet to a byte buffer.
     */
    public void encode(FriendlyByteBuf buf) {
        encodeUUID(buf);
        buf.writeBoolean(isEnslaved);

        // Write optional master UUID
        buf.writeBoolean(masterUUID != null);
        if (masterUUID != null) {
            buf.writeUUID(masterUUID);
        }

        // Write optional transport UUID
        buf.writeBoolean(transportUUID != null);
        if (transportUUID != null) {
            buf.writeUUID(transportUUID);
        }
    }

    /**
     * Decode the packet from a byte buffer.
     */
    public static PacketSyncEnslavement decode(FriendlyByteBuf buf) {
        UUID targetUUID = decodeUUID(buf);
        boolean isEnslaved = buf.readBoolean();

        UUID masterUUID = null;
        if (buf.readBoolean()) {
            masterUUID = buf.readUUID();
        }

        UUID transportUUID = null;
        if (buf.readBoolean()) {
            transportUUID = buf.readUUID();
        }

        return new PacketSyncEnslavement(
            targetUUID,
            masterUUID,
            transportUUID,
            isEnslaved
        );
    }

    /**
     * Apply the enslavement sync to a player.
     *
     * Note: This is primarily for CLIENT-SIDE visual/state updates.
     * The actual enslavement logic is handled server-side.
     */
    @Override
    @OnlyIn(Dist.CLIENT)
    protected void applySync(Player player) {
        // Client-side state awareness (for UI indicators, animations)
        // The client doesn't directly manipulate enslavement state
        // It receives updates from entity syncs
    }

    @Override
    @OnlyIn(Dist.CLIENT)
    protected void queueForRetry() {
        SyncManager.queueEnslavementSync(
            playerUUID,
            masterUUID,
            transportUUID,
            isEnslaved
        );
    }

    // Getters

    public UUID getTargetUUID() {
        return playerUUID;
    }

    public UUID getMasterUUID() {
        return masterUUID;
    }

    public UUID getTransportUUID() {
        return transportUUID;
    }

    public boolean isEnslaved() {
        return isEnslaved;
    }
}
