import { assert } from "../../assert.js";
import { spline3_hermite } from "./spline3_hermite.js";

/**
 * Compute the parameter values `t` at which a cubic Hermite spline reaches its
 * minimum and maximum on `[0, 1]`. `t_at_min` is written to
 * `result[result_offset]`, `t_at_max` to `result[result_offset + result_stride]`.
 * Both values lie in `[0, 1]`.
 *
 * Companion to {@link spline3_hermite_bounds}, which writes the values; this
 * one writes the parameters at which those values are reached. Either function
 * does its own critical-point search — call whichever you actually need.
 *
 * @param {number[]|Float32Array|Float64Array} result
 * @param {number} result_offset
 * @param {number} result_stride
 * @param {number} p0
 * @param {number} p1
 * @param {number} m0
 * @param {number} m1
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export function spline3_hermite_bounds_t(
    result,
    result_offset,
    result_stride,
    p0, p1, m0, m1
) {
    assert.greaterThan(result_stride, 0, 'result_stride must be greater than 0');
    assert.isInteger(result_stride, 'result_stride');

    // Derivative of the Hermite polynomial:
    //   3 t² (m0 + m1 + 2 p0 - 2 p1) - 2 t (2 m0 + m1 + 3 p0 - 3 p1) + m0
    const a = 3 * (m0 + m1 + 2 * p0 - 2 * p1);
    const b = -2 * (2 * m0 + m1 + 3 * p0 - 3 * p1);
    const c = m0;

    let min, max, t_at_min, t_at_max;
    if (p0 <= p1) {
        min = p0; t_at_min = 0;
        max = p1; t_at_max = 1;
    } else {
        min = p1; t_at_min = 1;
        max = p0; t_at_max = 0;
    }

    if (Math.abs(a) < 1e-12) {

        if (Math.abs(b) >= 1e-12) {
            const t = -c / b;

            if (0 < t && t < 1) {
                const value = spline3_hermite(t, p0, p1, m0, m1);

                if (value < min) {
                    min = value;
                    t_at_min = t;
                }
                if (value > max) {
                    max = value;
                    t_at_max = t;
                }
            }
        }

    } else {

        const b2ac = b * b - 4 * c * a;

        if (b2ac >= 0) {
            const sqrtb2ac = Math.sqrt(b2ac);

            const t1 = (-b + sqrtb2ac) / (2 * a);

            if (0 < t1 && t1 < 1) {
                const value = spline3_hermite(t1, p0, p1, m0, m1);

                if (value < min) {
                    min = value;
                    t_at_min = t1;
                }
                if (value > max) {
                    max = value;
                    t_at_max = t1;
                }
            }

            const t2 = (-b - sqrtb2ac) / (2 * a);

            if (0 < t2 && t2 < 1) {
                const value = spline3_hermite(t2, p0, p1, m0, m1);

                if (value < min) {
                    min = value;
                    t_at_min = t2;
                }
                if (value > max) {
                    max = value;
                    t_at_max = t2;
                }
            }
        }
    }

    result[result_offset] = t_at_min;
    result[result_offset + result_stride] = t_at_max;
}
