import { CapsuleShape3D } from "../CapsuleShape3D.js";
import { CylinderShape3D } from "../CylinderShape3D.js";
import { SphereShape3D } from "../SphereShape3D.js";
import { TransformedShape3D } from "../TransformedShape3D.js";
import { UnionShape3D } from "../UnionShape3D.js";
import { UnitCubeShape3D } from "../UnitCubeShape3D.js";
import { UnitSphereShape3D } from "../UnitSphereShape3D.js";
import { shape_from_json } from "./shape_from_json.js";
import { shape_to_json } from "./shape_to_json.js";

export const type_adapters = {
    'cube': {
        read() {
            return UnitCubeShape3D.INSTANCE;
        },
        write() {
            return {};
        }
    },
    'sphere': {
        read({ radius } = {}) {
            // Backward-compatible: legacy 'sphere' entries have no radius and
            // map to the unit-sphere singleton. A radius of 1 is also treated
            // as the unit sphere so re-saved unit spheres keep sharing INSTANCE.
            if (radius === undefined || radius === 1) {
                return UnitSphereShape3D.INSTANCE;
            }
            return SphereShape3D.from(radius);
        },
        /**
         * @param {SphereShape3D} object
         */
        write(object) {
            // Omit radius for the unit case to keep the serialized form
            // byte-identical to the pre-SphereShape3D 'sphere' tag.
            return object.radius === 1 ? {} : { radius: object.radius };
        }
    },
    'capsule': {
        read({ radius, height }) {
            return CapsuleShape3D.from(radius, height);
        },
        /**
         *
         * @param {CapsuleShape3D} object
         */
        write(object) {
            return {
                radius: object.radius,
                height: object.height
            };
        }
    },
    'cylinder': {
        read({ radius, height }) {
            return CylinderShape3D.from(radius, height);
        },
        /**
         *
         * @param {CylinderShape3D} object
         */
        write(object) {
            return {
                radius: object.radius,
                height: object.height
            };
        }
    },
    'transform': {
        read({ transform, subject }) {
            const subject_shape = shape_from_json(subject);

            return TransformedShape3D.from_m4(subject_shape, transform);
        },
        /**
         *
         * @param {TransformedShape3D} object
         */
        write(object) {
            return {
                subject: shape_to_json(object.subject),
                transform: Array.from(object.transform)
            };
        }
    },
    'union': {
        read({ members }) {
            const member_shapes = members.map(shape_from_json);

            return UnionShape3D.from(member_shapes);
        },
        /**
         *
         * @param {UnionShape3D} object
         */
        write(object) {
            return {
                members: object.children.map(shape_to_json)
            };
        }
    }
};
