import { BinaryClassSerializationAdapter } from "../../ecs/storage/binary/BinaryClassSerializationAdapter.js";
import { RigidBody } from "./RigidBody.js";

/**
 * Binary serialization for {@link RigidBody}.
 *
 * Only the configurable / persistent fields are written. Transient runtime state
 * (`_bodyId`, `sleepState`, accumulated force/torque) is owned by the
 * {@link PhysicsSystem} and recomputed on link — serialising it would tie the
 * stream to a particular world instance.
 */
export class RigidBodySerializationAdapter extends BinaryClassSerializationAdapter {

    klass = RigidBody;
    version = 0;

    /**
     *
     * @param {BinaryBuffer} buffer
     * @param {RigidBody} value
     */
    serialize(buffer, value) {
        buffer.writeUint8(value.kind);

        buffer.writeFloat64(value.linearVelocity.x);
        buffer.writeFloat64(value.linearVelocity.y);
        buffer.writeFloat64(value.linearVelocity.z);

        buffer.writeFloat64(value.angularVelocity.x);
        buffer.writeFloat64(value.angularVelocity.y);
        buffer.writeFloat64(value.angularVelocity.z);

        buffer.writeFloat64(value.mass);

        buffer.writeFloat64(value.inverseInertiaLocal.x);
        buffer.writeFloat64(value.inverseInertiaLocal.y);
        buffer.writeFloat64(value.inverseInertiaLocal.z);

        buffer.writeFloat64(value.linearDamping);
        buffer.writeFloat64(value.angularDamping);
        buffer.writeFloat64(value.gravityScale);

        buffer.writeUint32(value.layer >>> 0);
        buffer.writeUint32(value.mask >>> 0);
        buffer.writeUint32(value.flags >>> 0);
    }

    /**
     *
     * @param {BinaryBuffer} buffer
     * @param {RigidBody} value
     */
    deserialize(buffer, value) {
        value.kind = buffer.readUint8();

        const lvx = buffer.readFloat64();
        const lvy = buffer.readFloat64();
        const lvz = buffer.readFloat64();
        value.linearVelocity.set(lvx, lvy, lvz);

        const avx = buffer.readFloat64();
        const avy = buffer.readFloat64();
        const avz = buffer.readFloat64();
        value.angularVelocity.set(avx, avy, avz);

        value.mass = buffer.readFloat64();

        const iix = buffer.readFloat64();
        const iiy = buffer.readFloat64();
        const iiz = buffer.readFloat64();
        value.inverseInertiaLocal.set(iix, iiy, iiz);

        value.linearDamping = buffer.readFloat64();
        value.angularDamping = buffer.readFloat64();
        value.gravityScale = buffer.readFloat64();

        // `| 0` back to the signed int32 in-memory form the fields use (e.g. the
        // default mask is `0xFFFFFFFF | 0 === -1`). Reading the raw unsigned value
        // would make a round-tripped body compare unequal to a fresh one under
        // RigidBody.equals()'s strict ===, denting reset-to-snapshot determinism.
        value.layer = buffer.readUint32() | 0;
        value.mask = buffer.readUint32() | 0;
        value.flags = buffer.readUint32() | 0;
    }
}
