import { CubicEase, EasingFunction } from "../../Animations/easing.js";
import { Animation } from "../../Animations/animation.js";
/**
 * Animate camera property changes with an interpolation effect
 * @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors/cameraBehaviors
 */
export class InterpolatingBehavior {
    /**
     * Gets the name of the behavior.
     */
    get name() {
        return "Interpolating";
    }
    /**
     * Initializes the behavior
     */
    constructor() {
        /**
         * The easing function to use for interpolation
         */
        this.easingFunction = new CubicEase();
        /**
         * The easing mode (default is EASINGMODE_EASEINOUT)
         */
        this.easingMode = EasingFunction.EASINGMODE_EASEINOUT;
        /**
         * Duration of the animation in milliseconds
         */
        this.transitionDuration = 450;
        this._attachedCamera = null;
        this._animatables = new Map();
        this.easingFunction.setEasingMode(this.easingMode);
    }
    /**
     * Initializes the behavior
     */
    init() {
        // Nothing to do on init
    }
    /**
     * Attaches the behavior to a camera
     * @param camera The camera to attach to
     */
    attach(camera) {
        this._attachedCamera = camera;
    }
    /**
     * Detaches the behavior from the camera
     */
    detach() {
        if (!this._attachedCamera) {
            return;
        }
        this.stopAllAnimations();
        this._attachedCamera = null;
    }
    get isInterpolating() {
        return this._animatables.size > 0;
    }
    /**
     * Stops and removes all animations
     */
    stopAllAnimations() {
        if (this._attachedCamera) {
            this._animatables.forEach((animatable) => animatable.stop());
        }
        this._animatables.clear();
        this._promiseResolve?.();
        this._promiseResolve = undefined;
    }
    updateProperties(properties) {
        properties.forEach((value, key) => {
            if (value !== undefined) {
                const animatable = this._animatables.get(String(key));
                animatable && (animatable.target = value);
            }
        });
    }
    async animatePropertiesAsync(properties, transitionDuration = this.transitionDuration, easingFn = this.easingFunction) {
        const promise = new Promise((resolve) => {
            this._promiseResolve = resolve;
            this.stopAllAnimations();
            if (!this._attachedCamera) {
                this._promiseResolve = undefined;
                return resolve();
            }
            const camera = this._attachedCamera;
            const scene = camera.getScene();
            const checkClear = (animation) => {
                this._animatables.delete(animation);
                if (this._animatables.size === 0) {
                    this._promiseResolve = undefined;
                    resolve();
                }
            };
            properties.forEach((value, key) => {
                if (value !== undefined) {
                    const propertyName = String(key);
                    const animation = Animation.CreateAnimation(propertyName, GetAnimationType(value), 60, easingFn);
                    const animatable = Animation.TransitionTo(propertyName, value, camera, scene, 60, animation, transitionDuration, () => checkClear(propertyName));
                    if (animatable) {
                        this._animatables.set(propertyName, animatable);
                    }
                }
            });
        });
        return await promise;
    }
}
// Structural type-guards (no instanceof)
function IsQuaternionLike(v) {
    return v != null && typeof v.x === "number" && typeof v.y === "number" && typeof v.z === "number" && typeof v.w === "number";
}
function IsMatrixLike(v) {
    return v != null && (Array.isArray(v.m) || typeof v.m === "object");
}
function IsVector3Like(v) {
    return v != null && typeof v.x === "number" && typeof v.y === "number" && typeof v.z === "number";
}
function IsVector2Like(v) {
    return v != null && typeof v.x === "number" && typeof v.y === "number";
}
function IsColor3Like(v) {
    return v != null && typeof v.r === "number" && typeof v.g === "number" && typeof v.b === "number";
}
function IsColor4Like(v) {
    return v != null && typeof v.r === "number" && typeof v.g === "number" && typeof v.b === "number" && typeof v.a === "number";
}
function IsSizeLike(v) {
    return v != null && typeof v.width === "number" && typeof v.height === "number";
}
const GetAnimationType = (value) => {
    if (IsQuaternionLike(value)) {
        return Animation.ANIMATIONTYPE_QUATERNION;
    }
    if (IsMatrixLike(value)) {
        return Animation.ANIMATIONTYPE_MATRIX;
    }
    if (IsVector3Like(value)) {
        return Animation.ANIMATIONTYPE_VECTOR3;
    }
    if (IsVector2Like(value)) {
        return Animation.ANIMATIONTYPE_VECTOR2;
    }
    if (IsColor3Like(value)) {
        return Animation.ANIMATIONTYPE_COLOR3;
    }
    if (IsColor4Like(value)) {
        return Animation.ANIMATIONTYPE_COLOR4;
    }
    if (IsSizeLike(value)) {
        return Animation.ANIMATIONTYPE_SIZE;
    }
    // Fallback to float for numbers and unknown shapes
    return Animation.ANIMATIONTYPE_FLOAT;
};
//# sourceMappingURL=interpolatingBehavior.js.map