import { Vector3 } from '@zephyr3d/base';

/**
 * Base class for spring bone colliders.
 *
 * @public
 */ class SpringBoneCollider {
}
/**
 * Sphere collider for spring bones.
 *
 * @public
 */ class SphereCollider extends SpringBoneCollider {
    /** Center position in world space */ _center;
    /** Sphere radius */ _radius;
    /** Optional bone node to follow */ _bone;
    /** Local offset from bone (if bone is set) */ _localOffset;
    /**
   * Create a sphere collider.
   *
   * @param center - Center position in world space (or local offset if bone is provided)
   * @param radius - Sphere radius
   * @param bone - Optional bone node to follow
   */ constructor(center, radius, bone = null){
        super();
        this._center = center.clone();
        this._radius = Math.max(0, radius);
        this._bone = bone;
        this._localOffset = bone ? center.clone() : new Vector3();
    }
    /**
   * Get/set center position.
   */ get center() {
        if (this._bone) {
            // Calculate world position from bone
            const worldPos = new Vector3();
            const matrix = this._bone.worldMatrix;
            const offset = this._localOffset;
            worldPos.x = matrix.m00 * offset.x + matrix.m01 * offset.y + matrix.m02 * offset.z + matrix.m03;
            worldPos.y = matrix.m10 * offset.x + matrix.m11 * offset.y + matrix.m12 * offset.z + matrix.m13;
            worldPos.z = matrix.m20 * offset.x + matrix.m21 * offset.y + matrix.m22 * offset.z + matrix.m23;
            return worldPos;
        }
        return this._center;
    }
    set center(value) {
        if (this._bone) {
            this._localOffset.set(value);
        } else {
            this._center.set(value);
        }
    }
    /**
   * Get/set radius.
   */ get radius() {
        return this._radius;
    }
    set radius(value) {
        this._radius = Math.max(0, value);
    }
    /**
   * Get/set bone node.
   */ get bone() {
        return this._bone;
    }
    set bone(value) {
        this._bone = value;
    }
    /**
   * Test collision with a point and resolve it.
   */ collide(position, radius) {
        const center = this.center;
        const direction = Vector3.sub(position, center, new Vector3());
        const distance = direction.magnitude;
        const minDistance = this._radius + radius;
        if (distance < minDistance && distance > 0.000001) {
            // Collision detected, push the point out
            direction.scaleBy(1 / distance);
            const penetration = minDistance - distance;
            position.addBy(Vector3.scale(direction, penetration, new Vector3()));
            return true;
        }
        return false;
    }
}
/**
 * Capsule collider for spring bones.
 *
 * @remarks
 * A capsule is defined by two sphere centers and a radius.
 * Useful for limbs like arms and legs.
 *
 * @public
 */ class CapsuleCollider extends SpringBoneCollider {
    /** Start point in world space */ _start;
    /** End point in world space */ _end;
    /** Capsule radius */ _radius;
    /** Optional bone node for start point */ _startBone;
    /** Optional bone node for end point */ _endBone;
    /** Local offset for start point */ _startOffset;
    /** Local offset for end point */ _endOffset;
    /**
   * Create a capsule collider.
   *
   * @param start - Start point in world space (or local offset if startBone is provided)
   * @param end - End point in world space (or local offset if endBone is provided)
   * @param radius - Capsule radius
   * @param startBone - Optional bone node for start point
   * @param endBone - Optional bone node for end point
   */ constructor(start, end, radius, startBone = null, endBone = null){
        super();
        this._start = start.clone();
        this._end = end.clone();
        this._radius = Math.max(0, radius);
        this._startBone = startBone;
        this._endBone = endBone;
        this._startOffset = startBone ? start.clone() : new Vector3();
        this._endOffset = endBone ? end.clone() : new Vector3();
    }
    /**
   * Get start point in world space.
   */ get start() {
        if (this._startBone) {
            const worldPos = new Vector3();
            const matrix = this._startBone.worldMatrix;
            const offset = this._startOffset;
            worldPos.x = matrix.m00 * offset.x + matrix.m01 * offset.y + matrix.m02 * offset.z + matrix.m03;
            worldPos.y = matrix.m10 * offset.x + matrix.m11 * offset.y + matrix.m12 * offset.z + matrix.m13;
            worldPos.z = matrix.m20 * offset.x + matrix.m21 * offset.y + matrix.m22 * offset.z + matrix.m23;
            return worldPos;
        }
        return this._start;
    }
    /**
   * Get end point in world space.
   */ get end() {
        if (this._endBone) {
            const worldPos = new Vector3();
            const matrix = this._endBone.worldMatrix;
            const offset = this._endOffset;
            worldPos.x = matrix.m00 * offset.x + matrix.m01 * offset.y + matrix.m02 * offset.z + matrix.m03;
            worldPos.y = matrix.m10 * offset.x + matrix.m11 * offset.y + matrix.m12 * offset.z + matrix.m13;
            worldPos.z = matrix.m20 * offset.x + matrix.m21 * offset.y + matrix.m22 * offset.z + matrix.m23;
            return worldPos;
        }
        return this._end;
    }
    /**
   * Get/set radius.
   */ get radius() {
        return this._radius;
    }
    set radius(value) {
        this._radius = Math.max(0, value);
    }
    /**
   * Test collision with a point and resolve it.
   */ collide(position, radius) {
        const start = this.start;
        const end = this.end;
        // Calculate closest point on capsule line segment
        const line = Vector3.sub(end, start, new Vector3());
        const lineLength = line.magnitude;
        if (lineLength < 0.000001) {
            // Degenerate capsule, treat as sphere
            const direction = Vector3.sub(position, start, new Vector3());
            const distance = direction.magnitude;
            const minDistance = this._radius + radius;
            if (distance < minDistance && distance > 0.000001) {
                direction.scaleBy(1 / distance);
                const penetration = minDistance - distance;
                position.addBy(Vector3.scale(direction, penetration, new Vector3()));
                return true;
            }
            return false;
        }
        const lineDir = Vector3.scale(line, 1 / lineLength, new Vector3());
        const toPoint = Vector3.sub(position, start, new Vector3());
        const t = Math.max(0, Math.min(lineLength, Vector3.dot(toPoint, lineDir)));
        // Closest point on line segment
        const closestPoint = Vector3.add(start, Vector3.scale(lineDir, t, new Vector3()), new Vector3());
        // Check distance from closest point
        const direction = Vector3.sub(position, closestPoint, new Vector3());
        const distance = direction.magnitude;
        const minDistance = this._radius + radius;
        if (distance < minDistance && distance > 0.000001) {
            // Collision detected, push the point out
            direction.scaleBy(1 / distance);
            const penetration = minDistance - distance;
            position.addBy(Vector3.scale(direction, penetration, new Vector3()));
            return true;
        }
        return false;
    }
}

export { CapsuleCollider, SphereCollider, SpringBoneCollider };
//# sourceMappingURL=spring_bone_collider.js.map
