// Generated by delombok at Tue Dec 16 19:36:13 UTC 2025
package net.md_5.bungee.forge;

import com.google.common.base.Preconditions;
import java.util.ArrayDeque;
import java.util.Map;
import lombok.NonNull;
import net.md_5.bungee.UserConnection;
import net.md_5.bungee.protocol.packet.PluginMessage;

/**
 * Handles the Forge Client data and handshake procedure.
 */
public class ForgeClientHandler {
    @NonNull
    private final UserConnection con;
    /**
     * The users' mod list.
     */
    private Map<String, String> clientModList = null;
    private final ArrayDeque<PluginMessage> packetQueue = new ArrayDeque<PluginMessage>();
    @NonNull
    private ForgeClientHandshakeState state = ForgeClientHandshakeState.HELLO;
    private PluginMessage serverModList = null;
    private PluginMessage serverIdList = null;
    /**
     * Gets or sets a value indicating whether the '\00FML\00' token was found
     * in the handshake.
     */
    private boolean fmlTokenInHandshake = false;

    /**
     * Handles the Forge packet.
     *
     * @param message The Forge Handshake packet to handle.
     * @throws IllegalArgumentException if invalid packet received
     */
    public void handle(PluginMessage message) throws IllegalArgumentException {
        if (!message.getTag().equalsIgnoreCase(ForgeConstants.FML_HANDSHAKE_TAG)) {
            throw new IllegalArgumentException("Expecting a Forge Handshake packet.");
        }
        message.setAllowExtendedPacket(true); // FML allows extended packets so this must be enabled
        ForgeClientHandshakeState prevState = state;
        Preconditions.checkState(packetQueue.size() < 128, "Forge packet queue too big!");
        packetQueue.add(message);
        state = state.send(message, con);
        if (state != prevState) // state finished, send packets
         {
            synchronized (packetQueue) {
                while (!packetQueue.isEmpty()) {
                    ForgeLogger.logClient(ForgeLogger.LogDirection.SENDING, prevState.name(), packetQueue.getFirst());
                    con.getForgeServerHandler().receive(packetQueue.removeFirst());
                }
            }
        }
    }

    /**
     * Receives a {@link PluginMessage} from ForgeServer to pass to Client.
     *
     * @param message The message to being received.
     * @throws IllegalArgumentException if invalid packet received
     */
    public void receive(PluginMessage message) throws IllegalArgumentException {
        state = state.handle(message, con);
    }

    /**
     * Resets the client handshake state to HELLO, and, if we know the handshake
     * has been completed before, send the reset packet.
     */
    public void resetHandshake() {
        state = ForgeClientHandshakeState.HELLO;
        con.unsafe().sendPacket(ForgeConstants.FML_RESET_HANDSHAKE);
    }

    /**
     * Sends the server mod list to the client, or stores it for sending later.
     *
     * @param modList The {@link PluginMessage} to send to the client containing
     * the mod list.
     * @throws IllegalArgumentException Thrown if the {@link PluginMessage} was
     * not as expected.
     */
    public void setServerModList(PluginMessage modList) throws IllegalArgumentException {
        if (!modList.getTag().equalsIgnoreCase(ForgeConstants.FML_HANDSHAKE_TAG) || modList.getData()[0] != 2) {
            throw new IllegalArgumentException("modList");
        }
        this.serverModList = modList;
    }

    /**
     * Sends the server ID list to the client, or stores it for sending later.
     *
     * @param idList The {@link PluginMessage} to send to the client containing
     * the ID list.
     * @throws IllegalArgumentException Thrown if the {@link PluginMessage} was
     * not as expected.
     */
    public void setServerIdList(PluginMessage idList) throws IllegalArgumentException {
        if (!idList.getTag().equalsIgnoreCase(ForgeConstants.FML_HANDSHAKE_TAG) || idList.getData()[0] != 3) {
            throw new IllegalArgumentException("idList");
        }
        this.serverIdList = idList;
    }

    /**
     * Returns whether the handshake is complete.
     *
     * @return <code>true</code> if the handshake has been completed.
     */
    public boolean isHandshakeComplete() {
        return this.state == ForgeClientHandshakeState.DONE;
    }

    public void setHandshakeComplete() {
        this.state = ForgeClientHandshakeState.DONE;
    }

    /**
     * Returns whether we know if the user is a forge user. In FML 1.8, a "FML"
     * token is included in the initial handshake. We can use that to determine
     * if the user is a Forge 1.8 user.
     *
     * @return <code>true</code> if the user is a forge user.
     */
    public boolean isForgeUser() {
        return fmlTokenInHandshake || clientModList != null;
    }

    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public ForgeClientHandler(@NonNull final UserConnection con) {
        if (con == null) {
            throw new java.lang.NullPointerException("con is marked non-null but is null");
        }
        this.con = con;
    }

    /**
     * The users' mod list.
     */
    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public Map<String, String> getClientModList() {
        return this.clientModList;
    }

    /**
     * The users' mod list.
     */
    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    void setClientModList(final Map<String, String> clientModList) {
        this.clientModList = clientModList;
    }

    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    void setState(@NonNull final ForgeClientHandshakeState state) {
        if (state == null) {
            throw new java.lang.NullPointerException("state is marked non-null but is null");
        }
        this.state = state;
    }

    /**
     * Gets or sets a value indicating whether the '\00FML\00' token was found
     * in the handshake.
     */
    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public boolean isFmlTokenInHandshake() {
        return this.fmlTokenInHandshake;
    }

    /**
     * Gets or sets a value indicating whether the '\00FML\00' token was found
     * in the handshake.
     */
    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public void setFmlTokenInHandshake(final boolean fmlTokenInHandshake) {
        this.fmlTokenInHandshake = fmlTokenInHandshake;
    }
}
