import { Quaternion } from '@zephyr3d/base';
import { SpringSystemController } from './controller.js';

const _quat = new Quaternion();
function createTransformAccess(obj) {
    return {
        getWorldPosition () {
            return obj.getWorldPosition();
        },
        getWorldRotation () {
            const q = new Quaternion();
            obj.worldMatrix.decompose(null, q, null);
            return q;
        },
        getLocalPosition () {
            return obj.position.clone();
        },
        getLocalRotation () {
            return obj.rotation.clone();
        },
        getLocalScale () {
            return obj.scale.clone();
        },
        setWorldPosition (p) {
            if (obj.parent) {
                obj.position = obj.parent.invWorldMatrix.transformPointAffine(p);
            } else {
                obj.position.set(p);
            }
        },
        setWorldRotation (q) {
            // Convert world rotation to local: localRot = inverse(parentWorldRot) * worldRot
            if (obj.parent) {
                obj.parent.worldMatrix.decompose(null, _quat, null);
                Quaternion.multiply(Quaternion.inverse(_quat), q, obj.rotation);
            } else {
                obj.rotation.set(q);
            }
        },
        setLocalPosition (p) {
            obj.position.set(p);
        },
        setLocalRotation (q) {
            obj.rotation.set(q);
        },
        setLocalScale (s) {
            obj.scale.set(s);
        }
    };
}
/**
 * Physics engine for spring-based particle simulation
 * Uses Verlet integration and iterative constraint solving
 *
 * @public
 */ class SpringSystem2 {
    _controller;
    constructor(options, chainConfig, colliders, grabbers, flatPlanes){
        const rootPoints = [];
        const boneNodes = [];
        const pointTransforms = [];
        let index = 0;
        for (const chain of chainConfig.chains){
            const chainNodes = this.collectChainNodes(chain.start, chain.end);
            for(let i = 0; i < chainNodes.length; i++){
                const node = chainNodes[i];
                const boneNode = {
                    index: index++,
                    position: node.getWorldPosition(),
                    children: [],
                    isFixed: i === 0,
                    depth: i
                };
                boneNodes.push(boneNode);
                pointTransforms.push(createTransformAccess(node));
                if (i > 0) {
                    boneNodes[boneNodes.length - 2].children.push(boneNode);
                }
                if (i === 0) {
                    rootPoints.push(boneNode);
                }
            }
        }
        const systemRoot = createTransformAccess(chainConfig.systemRoot);
        this._controller = new SpringSystemController(options);
        this._controller.initialize(systemRoot, rootPoints, pointTransforms, colliders, grabbers, flatPlanes);
    }
    get controller() {
        return this._controller;
    }
    collectChainNodes(start, end) {
        if (!start.isParentOf(end)) {
            throw new Error('Invalid chain: end node must be a descendant of start node');
        }
        const nodes = [];
        let current = end;
        for(;;){
            nodes.unshift(current);
            if (current === start) {
                break;
            }
            current = current.parent;
        }
        return nodes;
    }
    /**
   * Updates the physics simulation
   * @param deltaTime - Time step in seconds
   */ update(deltaTime) {
        // Clamp deltaTime to prevent instability
        const dt = Math.min(deltaTime, 0.033); // Max 30 FPS
        // simulation
        this._controller.step(dt);
    }
}

export { SpringSystem2, createTransformAccess };
//# sourceMappingURL=spring_system.js.map
