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

/**
 * Binary serialization for {@link Joint}.
 *
 * Writes the configurable / persistent fields: the two anchor entities, the
 * local anchor points and basis frames, and the per-DOF mode + limit / spring /
 * motor config. Transient runtime state owned by the {@link PhysicsSystem} —
 * the warm-start accumulator (`dofImpulse`) and the resolved `_bodyIdA` /
 * `_bodyIdB` / `_jointId` — is deliberately excluded; it is recomputed on
 * `link_joint`, and serialising it would tie the stream to a particular world
 * instance.
 */
export class JointSerializationAdapter extends BinaryClassSerializationAdapter {

    klass = Joint;
    version = 0;

    /**
     * @param {BinaryBuffer} buffer
     * @param {Joint} value
     */
    serialize(buffer, value) {
        // Anchor entities — entityB may be JOINT_WORLD (−1), so signed.
        buffer.writeInt32(value.entityA);
        buffer.writeInt32(value.entityB);

        const la = value.localAnchorA, lb = value.localAnchorB;
        buffer.writeFloat64(la.x); buffer.writeFloat64(la.y); buffer.writeFloat64(la.z);
        buffer.writeFloat64(lb.x); buffer.writeFloat64(lb.y); buffer.writeFloat64(lb.z);

        const ba = value.localBasisA, bb = value.localBasisB;
        buffer.writeFloat64(ba[0]); buffer.writeFloat64(ba[1]); buffer.writeFloat64(ba[2]); buffer.writeFloat64(ba[3]);
        buffer.writeFloat64(bb[0]); buffer.writeFloat64(bb[1]); buffer.writeFloat64(bb[2]); buffer.writeFloat64(bb[3]);

        for (let i = 0; i < 6; i++) buffer.writeUint8(value.dofMode[i]);
        for (let i = 0; i < 6; i++) buffer.writeFloat64(value.dofLowerLimit[i]);
        for (let i = 0; i < 6; i++) buffer.writeFloat64(value.dofUpperLimit[i]);
        for (let i = 0; i < 6; i++) buffer.writeFloat64(value.dofStiffness[i]);
        for (let i = 0; i < 6; i++) buffer.writeFloat64(value.dofDamping[i]);
        for (let i = 0; i < 6; i++) buffer.writeFloat64(value.dofMotorTargetVelocity[i]);
        for (let i = 0; i < 6; i++) buffer.writeFloat64(value.dofMotorMaxForce[i]);

        buffer.writeUint8(value.swingTwist ? 1 : 0);
    }

    /**
     * @param {BinaryBuffer} buffer
     * @param {Joint} value
     */
    deserialize(buffer, value) {
        value.entityA = buffer.readInt32();
        value.entityB = buffer.readInt32();

        value.localAnchorA.set(buffer.readFloat64(), buffer.readFloat64(), buffer.readFloat64());
        value.localAnchorB.set(buffer.readFloat64(), buffer.readFloat64(), buffer.readFloat64());

        value.localBasisA.set(buffer.readFloat64(), buffer.readFloat64(), buffer.readFloat64(), buffer.readFloat64());
        value.localBasisB.set(buffer.readFloat64(), buffer.readFloat64(), buffer.readFloat64(), buffer.readFloat64());

        for (let i = 0; i < 6; i++) value.dofMode[i] = buffer.readUint8();
        for (let i = 0; i < 6; i++) value.dofLowerLimit[i] = buffer.readFloat64();
        for (let i = 0; i < 6; i++) value.dofUpperLimit[i] = buffer.readFloat64();
        for (let i = 0; i < 6; i++) value.dofStiffness[i] = buffer.readFloat64();
        for (let i = 0; i < 6; i++) value.dofDamping[i] = buffer.readFloat64();
        for (let i = 0; i < 6; i++) value.dofMotorTargetVelocity[i] = buffer.readFloat64();
        for (let i = 0; i < 6; i++) value.dofMotorMaxForce[i] = buffer.readFloat64();

        value.swingTwist = buffer.readUint8() !== 0;
    }
}
