import { assert } from "../../../core/assert.js";
import { lerp } from "../../../core/math/lerp.js";
import { spline3_hermite } from "../../../core/math/spline/spline3_hermite.js";
import { spline3_hermite_derivative } from "../../../core/math/spline/spline3_hermite_derivative.js";

/**
 * Subdivide a curve segment by introducing a new keyframe at a given normalized time.
 * Subdivision does not alter the curve shape in any way, it is intended primarily for editing purposes.
 *
 * @param {Keyframe} out keyframe to be added at the point of subdivision, its tangents, time and value will be overwritten
 * @param {Keyframe} key0 start of the segment
 * @param {Keyframe} key1 end of the segment
 * @param {number} t normalized time in [0..1] between key0 and key1 where new frame is to be inserted
 * @returns {Keyframe} `out`, for convenience
 *
 * @see AnimationCurve
 * @example
 *  const new_frame = animation_curve_subdivide(new Keyframe(), key0, key1, 0.5);
 *  curve.add(new_frame);
 */
export function animation_curve_subdivide(
    out,
    key0,
    key1,
    t
) {
    assert.isObject(out, 'out');
    assert.isObject(key0, 'key0');
    assert.isObject(key1, 'key1');

    assert.equal(out.isKeyframe,true,'out.isKeyframe !== true');
    assert.equal(key0.isKeyframe,true,'key0.isKeyframe !== true');
    assert.equal(key1.isKeyframe,true,'key1.isKeyframe !== true');

    assert.isNumber(t, 't');
    assert.ok(t >= 0 && t <= 1);

    const v0 = key0.value;
    const v1 = key1.value;

    const time_span = key1.time - key0.time;

    // Note that Keyframe tangents are normalized, so we denomalize them before using them
    const m0 = key0.outTangent * time_span;
    const m1 = key1.inTangent * time_span;

    const xm = spline3_hermite(
        t,
        v0, v1,
        m0, m1
    );
    const vm = spline3_hermite_derivative(
        t,
        v0, v1,
        m0, m1
    );

    out.time = lerp(key0.time, key1.time, t);
    out.value = xm;

    // re-normalize tangent
    const new_tangent = vm / time_span;

    out.inTangent = new_tangent;
    out.outTangent = new_tangent;

    return out;
}