import { dampedSpringStep } from "./dampedSpringStep.js";

/**
 * Damped spring with a value and velocity. Half-life parameterized.
 *
 * Convention: zeta = 1.0 is critically damped (no overshoot, fastest settle).
 * zeta < 1.0 under-damps (oscillation/ringing, useful for impact bounces).
 * zeta > 1.0 over-damps (slow approach, rarely useful in this engine).
 *
 * Use kick() to inject a velocity impulse (e.g. footfall impact, gunfire
 * recoil, knockback). Use stepTo() each fixed update to advance the
 * simulation toward a target value.
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export class Spring {
    /**
     * @param {number} [value] initial value
     * @param {number} [velocity] initial velocity
     */
    constructor(value = 0, velocity = 0) {
        this.value = value;
        this.velocity = velocity;
    }

    /**
     * Advance the spring toward `target`. Same half-life form used by the
     * pre-existing dampedSpringStep / criticallyDampedSpringStep helpers.
     *
     * @param {number} target target value
     * @param {number} halfLife seconds for the envelope to halve (smaller → snappier)
     * @param {number} zeta damping ratio (1=critical, <1=ring, >1=sluggish)
     * @param {number} dt
     */
    stepTo(target, halfLife, zeta, dt) {
        dampedSpringStep(this, target, halfLife, zeta, dt);
    }

    /**
     * Inject a velocity impulse. Use for one-shot events that should result
     * in an immediate "snap" (footfall down-kick, recoil push, blow-back).
     *
     * @param {number} impulse velocity to add
     */
    kick(impulse) {
        this.velocity += impulse;
    }

    /**
     * Instantaneously place the spring at a value with zero velocity. Use
     * when initializing or hard-resetting (e.g. teleport).
     *
     * @param {number} [value]
     */
    settle(value = 0) {
        this.value = value;
        this.velocity = 0;
    }

    /**
     * Displace value while preserving velocity. Used for "land here, then
     * decay" — see landing recovery where we want the impact dip displaced
     * but the velocity to ride out from there.
     *
     * @param {number} value
     */
    setValue(value) {
        this.value = value;
    }
}
