package com.tiedup.remake.network.base;

import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.tasks.PlayerStateTask;
import java.util.function.BiConsumer;
import java.util.function.Function;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

/**
 * Extended progress packet that includes role information.
 *
 * Used for tying/untying packets where we need to show different
 * progress text based on whether the player is the active party
 * (kidnapper/helper) or the passive party (victim).
 *
 * Subclasses only need to implement:
 * - decode() - static method returning the concrete type
 * - getTaskGetter() - returns the function to get the task from PlayerBindState
 * - getTaskSetter() - returns the function to set the task on PlayerBindState
 */
public abstract class AbstractProgressPacketWithRole
    extends AbstractProgressPacket
{

    protected final boolean isActiveRole;
    protected final String otherEntityName;

    /**
     * Create a new progress packet with role info.
     *
     * @param stateInfo Current time value (-1 for completion/cancel)
     * @param maxState Total duration in seconds
     * @param isActiveRole true if recipient is the active party (kidnapper/helper)
     * @param otherEntityName Name of the other party
     */
    protected AbstractProgressPacketWithRole(
        int stateInfo,
        int maxState,
        boolean isActiveRole,
        String otherEntityName
    ) {
        super(stateInfo, maxState);
        this.isActiveRole = isActiveRole;
        this.otherEntityName = otherEntityName != null ? otherEntityName : "";
    }

    public boolean isActiveRole() {
        return isActiveRole;
    }

    public String getOtherEntityName() {
        return otherEntityName;
    }

    @Override
    public void encode(FriendlyByteBuf buf) {
        super.encode(buf);
        buf.writeBoolean(isActiveRole);
        buf.writeUtf(otherEntityName);
    }

    /**
     * Static helper to decode all fields from buffer.
     * Subclasses should call this in their static decode() method.
     *
     * @param buf The buffer to read from
     * @return RolePacketData with all decoded fields
     */
    protected static RolePacketData decodeRoleFields(FriendlyByteBuf buf) {
        int stateInfo = buf.readInt();
        int maxState = buf.readInt();
        boolean isActiveRole = buf.readBoolean();
        String otherEntityName = buf.readUtf();
        return new RolePacketData(
            stateInfo,
            maxState,
            isActiveRole,
            otherEntityName
        );
    }

    /**
     * Data container for decoded packet fields.
     */
    protected record RolePacketData(
        int stateInfo,
        int maxState,
        boolean isActiveRole,
        String otherEntityName
    ) {}

    /**
     * Override to create task with role info.
     */
    @Override
    @OnlyIn(Dist.CLIENT)
    protected void handleProgressUpdate(PlayerBindState playerState) {
        if (stateInfo == -1) {
            // Task completed or cancelled - clear client-side state
            getTaskSetter().accept(playerState, null);
        } else {
            // Update or create client-side task
            PlayerStateTask task = getTaskGetter().apply(playerState);

            if (task == null || task.isOutdated()) {
                // Create new task state WITH ROLE INFO
                task = new PlayerStateTask(
                    maxState,
                    isActiveRole,
                    otherEntityName
                );
                getTaskSetter().accept(playerState, task);
            }

            // Update progress
            task.update(calculateElapsed());
        }
    }
}
