import { ResourceDescriptor, QueryDescriptor, With } from 'thyseus';
import { ColliderDesc } from "@dimforge/rapier3d";
import { Warehouse } from "@houseki-engine/core";
import { Geometry, GlobalTransform, Parent } from "@houseki-engine/scene";
import { Entity, Query, Res, With } from "thyseus";
import { MeshCollider } from "../../components";
import { PhysicsStore } from "../../resources";
export function createMeshColliders(warehouse: Res<Warehouse>, store: Res<PhysicsStore>, colliders: Query<[
    Entity,
    MeshCollider
]>, withParent: Query<[
    Entity,
    Parent
], With<MeshCollider>>, nodes: Query<[
    Entity,
    GlobalTransform
]>, geometries: Query<[
    Entity,
    Geometry
]>) {
    const ids: bigint[] = [];
    const parentIds = new Map<bigint, bigint>();
    for (const [entity, parent] of withParent) {
        entity.deserialize();
        parent.deserialize();
        parentIds.set(entity.id, parent.id);
        entity.serialize();
        parent.serialize();
    }
    for (const [entity, collider] of colliders) {
        entity.deserialize();
        collider.deserialize();
        ids.push(entity.id);
        let object = store.meshColliders.get(entity.id);
        let rigidbodyId = entity.id;
        let rigidbody = store.getRigidBody(rigidbodyId);
        if (!rigidbody) {
            const parentId = parentIds.get(entity.id);
            if (parentId) {
                rigidbodyId = parentId;
                rigidbody = store.getRigidBody(parentId);
            }
        }
        if (!rigidbody)
            continue;
        // Create new colliders
        if (!object || object.parent() !== rigidbody) {
            // Remove old collider
            if (object)
                store.world.removeCollider(object, true);
            const meshId = collider.meshId || entity.id;
            for (const [geometryEntity, geometry] of geometries) {
                geometryEntity.deserialize();
                geometry.deserialize();
                if (geometryEntity.id !== meshId)
                    continue;
                const vertices = geometry.positions.read(warehouse);
                const indices = geometry.indices.read(warehouse);
                if (!vertices || !indices)
                    continue;
                const scaledVertices = new Float32Array(vertices.length);
                // Scale vertices using global transform
                for (const [nodeEntity, globalTransform] of nodes) {
                    nodeEntity.deserialize();
                    globalTransform.deserialize();
                    if (nodeEntity.id !== rigidbodyId)
                        continue;
                    for (let i = 0; i < vertices.length; i += 3) {
                        const x = vertices[i] ?? 0;
                        const y = vertices[i + 1] ?? 0;
                        const z = vertices[i + 2] ?? 0;
                        scaledVertices[i] = x * globalTransform.scale.x;
                        scaledVertices[i + 1] = y * globalTransform.scale.y;
                        scaledVertices[i + 2] = z * globalTransform.scale.z;
                    }
                    nodeEntity.serialize();
                    globalTransform.serialize();
                }
                const colliderDesc = ColliderDesc.trimesh(scaledVertices, indices);
                object = store.world.createCollider(colliderDesc, rigidbody);
                store.meshColliders.set(entity.id, object);
                geometryEntity.serialize();
                geometry.serialize();
            }
        }
        entity.serialize();
        collider.serialize();
    }
    // Remove colliders that are no longer in use
    for (const id of store.meshColliders.keys()) {
        if (!ids.includes(id)) {
            const object = store.meshColliders.get(id);
            if (object)
                store.world.removeCollider(object, true);
            store.meshColliders.delete(id);
        }
    }
}
createMeshColliders.parameters = [new ResourceDescriptor(Warehouse), new ResourceDescriptor(PhysicsStore), new QueryDescriptor([Entity, MeshCollider]), new QueryDescriptor([Entity, Parent], new With(MeshCollider)), new QueryDescriptor([Entity, GlobalTransform]), new QueryDescriptor([Entity, Geometry])];
