// Generated by delombok at Tue Dec 16 19:35:15 UTC 2025
package net.md_5.bungee.protocol;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.BiConsumer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentStyle;
import net.md_5.bungee.nbt.NamedTag;
import net.md_5.bungee.nbt.Tag;
import net.md_5.bungee.nbt.TypedTag;
import net.md_5.bungee.nbt.limit.NBTLimiter;
import net.md_5.bungee.nbt.type.EndTag;
import net.md_5.bungee.protocol.data.NumberFormat;
import net.md_5.bungee.protocol.data.PlayerPublicKey;
import net.md_5.bungee.protocol.data.Property;
import net.md_5.bungee.protocol.util.Either;
import net.md_5.bungee.protocol.util.TagUtil;

public abstract class DefinedPacket {
    public static <T> T readNullable(Function<ByteBuf, T> reader, ByteBuf buf) {
        return buf.readBoolean() ? reader.apply(buf) : null;
    }

    public static <T> void writeNullable(T t0, BiConsumer<T, ByteBuf> writer, ByteBuf buf) {
        if (t0 != null) {
            buf.writeBoolean(true);
            writer.accept(t0, buf);
        } else {
            buf.writeBoolean(false);
        }
    }

    public static <T> T readLengthPrefixed(Function<ByteBuf, T> reader, ByteBuf buf, int maxSize) {
        int size = readVarInt(buf);
        if (size > maxSize) {
            throw new OverflowPacketException("Cannot read length prefixed with limit " + maxSize + " (got size of " + size + ")");
        }
        return reader.apply(buf.readSlice(size));
    }

    public static <T> void writeLengthPrefixed(T value, BiConsumer<T, ByteBuf> writer, ByteBuf buf, int maxSize) {
        ByteBuf tempBuffer = buf.alloc().buffer();
        try {
            writer.accept(value, tempBuffer);
            if (tempBuffer.readableBytes() > maxSize) {
                throw new OverflowPacketException("Cannot write length prefixed with limit " + maxSize + " (got size of " + tempBuffer.readableBytes() + ")");
            }
            writeVarInt(tempBuffer.readableBytes(), buf);
            buf.writeBytes(tempBuffer);
        } finally {
            tempBuffer.release();
        }
    }

    public static void writeString(String s, ByteBuf buf) {
        writeString(s, buf, Short.MAX_VALUE);
    }

    public static void writeString(String s, ByteBuf buf, int maxLength) {
        if (s.length() > maxLength) {
            throw new OverflowPacketException("Cannot send string longer than " + maxLength + " (got " + s.length() + " characters)");
        }
        byte[] b = s.getBytes(StandardCharsets.UTF_8);
        if (b.length > maxLength * 3) {
            throw new OverflowPacketException("Cannot send string longer than " + (maxLength * 3) + " (got " + b.length + " bytes)");
        }
        writeVarInt(b.length, buf);
        buf.writeBytes(b);
    }

    public static <T> T readStringMapKey(ByteBuf buf, Map<String, T> map) {
        String string = readString(buf);
        T result = map.get(string);
        Preconditions.checkArgument(result != null, "Unknown string key %s", string);
        return result;
    }

    public static String readString(ByteBuf buf) {
        return readString(buf, Short.MAX_VALUE);
    }

    public static String readString(ByteBuf buf, int maxLen) {
        int len = readVarInt(buf);
        if (len > maxLen * 3) {
            throw new OverflowPacketException("Cannot receive string longer than " + maxLen * 3 + " (got " + len + " bytes)");
        }
        String s = buf.readString(len, StandardCharsets.UTF_8);
        if (s.length() > maxLen) {
            throw new OverflowPacketException("Cannot receive string longer than " + maxLen + " (got " + s.length() + " characters)");
        }
        return s;
    }

    public static Either<String, BaseComponent> readEitherBaseComponent(ByteBuf buf, int protocolVersion, boolean string) {
        return (string) ? Either.left(readString(buf)) : Either.right(readBaseComponent(buf, protocolVersion));
    }

    public static BaseComponent readBaseComponent(ByteBuf buf, int protocolVersion) {
        return readBaseComponent(buf, Short.MAX_VALUE, protocolVersion);
    }

    public static BaseComponent readBaseComponent(ByteBuf buf, int maxStringLength, int protocolVersion) {
        if (protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3) {
            TypedTag nbt = (TypedTag) readTag(buf, protocolVersion);
            JsonElement json = TagUtil.toJson(nbt);
            return ChatSerializer.forVersion(protocolVersion).deserialize(json);
        } else {
            String string = readString(buf, maxStringLength);
            return ChatSerializer.forVersion(protocolVersion).deserialize(string);
        }
    }

    public static ComponentStyle readComponentStyle(ByteBuf buf, int protocolVersion) {
        TypedTag nbt = (TypedTag) readTag(buf, protocolVersion);
        JsonElement json = TagUtil.toJson(nbt);
        return ChatSerializer.forVersion(protocolVersion).deserializeStyle(json);
    }

    public static void writeEitherBaseComponent(Either<String, BaseComponent> message, ByteBuf buf, int protocolVersion) {
        if (message.isLeft()) {
            writeString(message.getLeft(), buf);
        } else {
            writeBaseComponent(message.getRight(), buf, protocolVersion);
        }
    }

    public static void writeBaseComponent(BaseComponent message, ByteBuf buf, int protocolVersion) {
        if (protocolVersion >= ProtocolConstants.MINECRAFT_1_20_3) {
            JsonElement json = ChatSerializer.forVersion(protocolVersion).toJson(message);
            TypedTag nbt = TagUtil.fromJson(json);
            writeTag(nbt, buf, protocolVersion);
        } else {
            String string = ChatSerializer.forVersion(protocolVersion).toString(message);
            writeString(string, buf);
        }
    }

    public static void writeComponentStyle(ComponentStyle style, ByteBuf buf, int protocolVersion) {
        JsonElement json = ChatSerializer.forVersion(protocolVersion).toJson(style);
        TypedTag nbt = TagUtil.fromJson(json);
        writeTag(nbt, buf, protocolVersion);
    }

    public static void writeArray(byte[] b, ByteBuf buf) {
        if (b.length > Short.MAX_VALUE) {
            throw new OverflowPacketException("Cannot send byte array longer than Short.MAX_VALUE (got " + b.length + " bytes)");
        }
        writeVarInt(b.length, buf);
        buf.writeBytes(b);
    }

    public static byte[] toArray(ByteBuf buf) {
        byte[] ret = new byte[buf.readableBytes()];
        buf.readBytes(ret);
        return ret;
    }

    public static byte[] readArray(ByteBuf buf) {
        return readArray(buf, buf.readableBytes());
    }

    public static byte[] readArray(ByteBuf buf, int limit) {
        int len = readVarInt(buf);
        if (len > limit) {
            throw new OverflowPacketException("Cannot receive byte array longer than " + limit + " (got " + len + " bytes)");
        }
        byte[] ret = new byte[len];
        buf.readBytes(ret);
        return ret;
    }

    public static int[] readVarIntArray(ByteBuf buf) {
        int len = readVarInt(buf);
        int[] ret = new int[len];
        for (int i = 0; i < len; i++) {
            ret[i] = readVarInt(buf);
        }
        return ret;
    }

    public static void writeStringArray(List<String> s, ByteBuf buf) {
        writeVarInt(s.size(), buf);
        for (String str : s) {
            writeString(str, buf);
        }
    }

    public static List<String> readStringArray(ByteBuf buf) {
        int len = readVarInt(buf);
        List<String> ret = new ArrayList<>(len);
        for (int i = 0; i < len; i++) {
            ret.add(readString(buf));
        }
        return ret;
    }

    public static int readVarInt(ByteBuf input) {
        return readVarInt(input, 5);
    }

    public static int readVarInt(ByteBuf input, int maxBytes) {
        int out = 0;
        int bytes = 0;
        byte in;
        while (true) {
            in = input.readByte();
            out |= (in & 127) << (bytes++ * 7);
            if (bytes > maxBytes) {
                throw new OverflowPacketException("VarInt too big (max " + maxBytes + ")");
            }
            if ((in & 128) != 128) {
                break;
            }
        }
        return out;
    }

    public static void writeVarInt(int value, ByteBuf output) {
        int part;
        while (true) {
            part = value & 127;
            value >>>= 7;
            if (value != 0) {
                part |= 128;
            }
            output.writeByte(part);
            if (value == 0) {
                break;
            }
        }
    }

    public static void setVarInt(int value, ByteBuf output, int pos, int len) {
        switch (len) {
        case 1: 
            output.setByte(pos, value);
            break;
        case 2: 
            output.setShort(pos, (value & 127 | 128) << 8 | (value >>> 7 & 127));
            break;
        case 3: 
            output.setMedium(pos, (value & 127 | 128) << 16 | (value >>> 7 & 127 | 128) << 8 | (value >>> 14 & 127));
            break;
        case 4: 
            output.setInt(pos, (value & 127 | 128) << 24 | (value >>> 7 & 127 | 128) << 16 | (value >>> 14 & 127 | 128) << 8 | (value >>> 21 & 127));
            break;
        case 5: 
            output.setInt(pos, (value & 127 | 128) << 24 | (value >>> 7 & 127 | 128) << 16 | (value >>> 14 & 127 | 128) << 8 | (value >>> 21 & 127 | 128));
            output.setByte(pos + 4, value >>> 28);
            break;
        default: 
            throw new IllegalArgumentException("Invalid varint len: " + len);
        }
    }

    public static int readVarShort(ByteBuf buf) {
        int low = buf.readUnsignedShort();
        int high = 0;
        if ((low & 32768) != 0) {
            low = low & 32767;
            high = buf.readUnsignedByte();
        }
        return ((high & 255) << 15) | low;
    }

    public static void writeVarShort(ByteBuf buf, int toWrite) {
        int low = toWrite & 32767;
        int high = (toWrite & 8355840) >> 15;
        if (high != 0) {
            low = low | 32768;
        }
        buf.writeShort(low);
        if (high != 0) {
            buf.writeByte(high);
        }
    }

    public static void writeUUID(UUID value, ByteBuf output) {
        output.writeLong(value.getMostSignificantBits());
        output.writeLong(value.getLeastSignificantBits());
    }

    public static UUID readUUID(ByteBuf input) {
        return new UUID(input.readLong(), input.readLong());
    }

    public static void writeProperties(Property[] properties, ByteBuf buf) {
        if (properties == null) {
            writeVarInt(0, buf);
            return;
        }
        writeVarInt(properties.length, buf);
        for (Property prop : properties) {
            writeString(prop.getName(), buf);
            writeString(prop.getValue(), buf);
            if (prop.getSignature() != null) {
                buf.writeBoolean(true);
                writeString(prop.getSignature(), buf);
            } else {
                buf.writeBoolean(false);
            }
        }
    }

    public static Property[] readProperties(ByteBuf buf) {
        Property[] properties = new Property[DefinedPacket.readVarInt(buf)];
        for (int j = 0; j < properties.length; j++) {
            String name = readString(buf);
            String value = readString(buf);
            if (buf.readBoolean()) {
                properties[j] = new Property(name, value, DefinedPacket.readString(buf));
            } else {
                properties[j] = new Property(name, value);
            }
        }
        return properties;
    }

    public static void writePublicKey(PlayerPublicKey publicKey, ByteBuf buf) {
        if (publicKey != null) {
            buf.writeBoolean(true);
            buf.writeLong(publicKey.getExpiry());
            writeArray(publicKey.getKey(), buf);
            writeArray(publicKey.getSignature(), buf);
        } else {
            buf.writeBoolean(false);
        }
    }

    public static PlayerPublicKey readPublicKey(ByteBuf buf) {
        if (buf.readBoolean()) {
            return new PlayerPublicKey(buf.readLong(), readArray(buf, 512), readArray(buf, 4096));
        }
        return null;
    }

    public static void writeNumberFormat(NumberFormat format, ByteBuf buf, int protocolVersion) {
        writeVarInt(format.getType().ordinal(), buf);
        switch (format.getType()) {
        case BLANK: 
            break;
        case STYLED: 
            writeComponentStyle((ComponentStyle) format.getValue(), buf, protocolVersion);
            break;
        case FIXED: 
            writeBaseComponent((BaseComponent) format.getValue(), buf, protocolVersion);
            break;
        }
    }

    public static NumberFormat readNumberFormat(ByteBuf buf, int protocolVersion) {
        int format = readVarInt(buf);
        switch (format) {
        case 0: 
            return new NumberFormat(NumberFormat.Type.BLANK, null);
        case 1: 
            return new NumberFormat(NumberFormat.Type.STYLED, readComponentStyle(buf, protocolVersion));
        case 2: 
            return new NumberFormat(NumberFormat.Type.FIXED, readBaseComponent(buf, protocolVersion));
        default: 
            throw new IllegalArgumentException("Unknown number format " + format);
        }
    }

    public static Tag readTag(ByteBuf input, int protocolVersion) {
        return readTag(input, protocolVersion, new NBTLimiter(1 << 21));
    }

    public static Tag readTag(ByteBuf input, int protocolVersion, NBTLimiter limiter) {
        DataInputStream in = new DataInputStream(new ByteBufInputStream(input));
        try {
            if (protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2) {
                byte type = in.readByte();
                if (type == 0) {
                    return EndTag.INSTANCE;
                } else {
                    return Tag.readById(type, in, limiter);
                }
            }
            NamedTag namedTag = new NamedTag();
            namedTag.read(in, limiter);
            return namedTag;
        } catch (IOException ex) {
            throw new RuntimeException("Exception reading tag", ex);
        }
    }

    public static void writeTag(Tag tag, ByteBuf output, int protocolVersion) {
        DataOutputStream out = new DataOutputStream(new ByteBufOutputStream(output));
        try {
            if (tag instanceof TypedTag) {
                TypedTag typedTag = (TypedTag) tag;
                out.writeByte(typedTag.getId());
                typedTag.write(out);
            } else {
                tag.write(out);
            }
        } catch (IOException ex) {
            throw new RuntimeException("Exception writing tag", ex);
        }
    }

    public static <E extends Enum<E>> void writeEnumSet(EnumSet<E> enumset, Class<E> oclass, ByteBuf buf) {
        E[] enums = oclass.getEnumConstants();
        BitSet bits = new BitSet(enums.length);
        for (int i = 0; i < enums.length; ++i) {
            bits.set(i, enumset.contains(enums[i]));
        }
        writeFixedBitSet(bits, enums.length, buf);
    }

    public static <E extends Enum<E>> EnumSet<E> readEnumSet(Class<E> oclass, ByteBuf buf) {
        E[] enums = oclass.getEnumConstants();
        BitSet bits = readFixedBitSet(enums.length, buf);
        EnumSet<E> set = EnumSet.noneOf(oclass);
        for (int i = 0; i < enums.length; ++i) {
            if (bits.get(i)) {
                set.add(enums[i]);
            }
        }
        return set;
    }

    public static BitSet readFixedBitSet(int i, ByteBuf buf) {
        byte[] bits = new byte[(i + 7) >> 3];
        buf.readBytes(bits);
        return BitSet.valueOf(bits);
    }

    public static void writeFixedBitSet(BitSet bits, int size, ByteBuf buf) {
        if (bits.length() > size) {
            throw new OverflowPacketException("BitSet too large (expected " + size + " got " + bits.size() + ")");
        }
        buf.writeBytes(Arrays.copyOf(bits.toByteArray(), (size + 7) >> 3));
    }

    public void read(ByteBuf buf) {
        throw new UnsupportedOperationException("Packet must implement read method");
    }

    public void read(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion) {
        read(buf, direction, protocolVersion);
    }

    public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
        read(buf);
    }

    public void write(ByteBuf buf) {
        throw new UnsupportedOperationException("Packet must implement write method");
    }

    public void write(ByteBuf buf, Protocol protocol, ProtocolConstants.Direction direction, int protocolVersion) {
        write(buf, direction, protocolVersion);
    }

    public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) {
        write(buf);
    }

    public Protocol nextProtocol() {
        return null;
    }

    public abstract void handle(AbstractPacketHandler handler) throws Exception;

    @Override
    public abstract boolean equals(Object obj);

    @Override
    public abstract int hashCode();

    @Override
    public abstract String toString();

    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public DefinedPacket() {
    }
}
