import { BoxCollider, CapsuleCollider, Collider, MeshCollider, SphereCollider } from "../../../../Collider.js";
import { GameObject } from "../../../../Component.js";
import { Rigidbody } from "../../../../RigidBody.js";
export class PhysicsExtension {
    get extensionName() { return "Physics"; }
    onExportObject(object, model, _context) {
        const rigidBodySources = GameObject.getComponents(object, Rigidbody).filter(c => c.enabled);
        // no triggers supported for now; large trigger areas seem to break VisionOS since they're still interactable and block OS UI
        const colliderSources = GameObject.getComponents(object, Collider).filter(c => c.enabled && !c.isTrigger);
        let rigidBody = rigidBodySources.length > 0 ? rigidBodySources[0] : null;
        const colliderSource = colliderSources.length > 0 ? colliderSources[0] : null;
        // we still need a RigidBody component for the object to participate in physics;
        // with only a Collider component it can only serve as trigger
        // see https://developer.apple.com/documentation/realitykit/collisioncomponent#overview        
        let temporaryRigidbody = undefined;
        if (colliderSource && !rigidBody) {
            rigidBody = new Rigidbody();
            rigidBody.isKinematic = true;
            temporaryRigidbody = rigidBody;
        }
        if (rigidBody) {
            model.addEventListener('serialize', (writer, _context) => {
                if (!rigidBody)
                    return;
                writer.appendLine();
                writer.beginBlock(`def RealityKitComponent "RigidBody"`, "{", true);
                // Gravity is enabled by default
                if (!rigidBody.useGravity) {
                    writer.appendLine(`bool gravityEnabled = 0`);
                }
                writer.appendLine(`uniform token info:id = "RealityKit.RigidBody"`);
                if (rigidBody.isKinematic) {
                    writer.appendLine(`token motionType = "Kinematic"`);
                }
                writer.beginBlock(`def RealityKitStruct "massFrame"`, "{", true);
                writer.appendLine(`float m_mass = ${rigidBody.mass}`);
                writer.beginBlock(`def RealityKitStruct "m_pose"`, "{", true);
                /* TODO: Apple has a concept of center of mass orientation, not sure what that means here or what an equivalent mapping would be */
                writer.appendLine(`float3 position = (${rigidBody.centerOfMass.x}, ${rigidBody.centerOfMass.y}, ${rigidBody.centerOfMass.z})`);
                writer.closeBlock("}");
                writer.closeBlock("}");
                if (colliderSources.length > 0) {
                    const colliderSource = colliderSources[0];
                    writer.beginBlock(`def RealityKitStruct "material"`, "{", true);
                    const mat = colliderSource.sharedMaterial;
                    if (mat && mat.dynamicFriction !== undefined)
                        writer.appendLine(`double dynamicFriction = ${colliderSource.sharedMaterial?.dynamicFriction}`);
                    if (mat && mat.bounciness !== undefined)
                        writer.appendLine(`double restitution = ${colliderSource.sharedMaterial?.bounciness}`);
                    // eslint-disable-next-line @typescript-eslint/no-deprecated
                    if (mat && mat.staticFriction !== undefined)
                        // eslint-disable-next-line @typescript-eslint/no-deprecated
                        writer.appendLine(`double staticFriction = ${colliderSource.sharedMaterial?.staticFriction}`);
                    writer.closeBlock("}");
                }
                writer.closeBlock("}");
            });
        }
        if (colliderSource) {
            // TODO: Apple only allows one collider, Unity allows many, are many typically used on each object though? What can we do here? combine them? take the first?
            model.addEventListener('serialize', (writer, _context) => {
                writer.beginBlock(`def RealityKitComponent "Collider"`, "{", true);
                // TODO: a group is needed for collisions, not sure what this controls though
                writer.appendLine(`uint group = 1`);
                writer.appendLine(`uniform token info:id = "RealityKit.Collider"`);
                // TODO: a mask is needed for collisions, this is the max value for int, possibly collision flags but i'm not sure what each bit means, or if we have that exported info from unity
                // This is coming from RealityComposerPro
                writer.appendLine(`uint mask = 4294967295`);
                const isTrigger = colliderSource.isTrigger; // not currently used, see comment above
                const typeName = isTrigger ? "Trigger" : "Default";
                writer.appendLine(`token type = "${typeName}"`);
                writer.beginBlock(`def RealityKitStruct "Shape"`, "{", true);
                if (colliderSource instanceof SphereCollider) {
                    const sphereCollider = colliderSource;
                    writer.appendLine(`token shapeType = "Sphere"`);
                    writer.appendLine(`float radius = ${sphereCollider.radius}`);
                }
                else if (colliderSource instanceof BoxCollider) {
                    const boxCollider = colliderSource;
                    writer.appendLine(`token shapeType = "Box"`);
                    writer.appendLine(`float3 extent = (${boxCollider.size.x}, ${boxCollider.size.y}, ${boxCollider.size.z})`);
                }
                else if (colliderSource instanceof CapsuleCollider) {
                    const capsuleCollider = colliderSource;
                    writer.appendLine(`token shapeType = "Capsule"`);
                    writer.appendLine(`float radius = ${capsuleCollider.radius}`);
                    writer.appendLine(`float height = ${capsuleCollider.height}`);
                }
                else if (colliderSource instanceof MeshCollider && colliderSource.sharedMesh?.geometry) {
                    // get the bounds of the mesh
                    const geo = colliderSource.sharedMesh.geometry;
                    if (!geo.boundingBox)
                        geo.computeBoundingBox();
                    const box = colliderSource.sharedMesh.geometry.boundingBox;
                    if (box) {
                        writer.appendLine(`token shapeType = "Box"`);
                        writer.appendLine(`float3 extent = (${box.max.x - box.min.x}, ${box.max.y - box.min.y}, ${box.max.z - box.min.z})`);
                        console.log("[USDZ] Only Box, Sphere, and Capsule colliders are supported in visionOS/iOS. MeshCollider will be exported as Box", colliderSource);
                    }
                }
                else {
                    console.warn("[USDZ] Only Box, Sphere, and Capsule colliders are supported in visionOS/iOS. Ignoring collider:", colliderSource);
                }
                writer.beginBlock(`def RealityKitStruct "pose"`, "{", true);
                // TODO: this is used for rotating the collider, I think this isn't necessary since all the changes happen in the parent transform from needle. Not positive about this though.
                writer.closeBlock("}");
                writer.closeBlock("}");
                writer.closeBlock("}");
            });
            if (colliderSources.length > 1) {
                console.log("WARNING: Multiple colliders detected. visionOS / iOS can only support objects with a single collider, only exporting the first collider: ", colliderSource);
            }
        }
    }
}
//# sourceMappingURL=PhysicsExtension.js.map