import { assert } from "../../assert.js";
import { max2 } from "../max2.js";
import { min2 } from "../min2.js";
import { spline3_bezier } from "./spline3_bezier.js";

/**
 * Compute bounds of a 3-rd degree bezier curve
 * Note that this is a 1d case solver
 * Lower bound will be written into result[offset], upper bounds will be written into result[offset+result_stride]
 * @see https://github.com/adobe-webplatform/Snap.svg/blob/c8e483c9694517e24b282f8f59f985629f4994ce/src/path.js#L856
 * @param {number[]|Float32Array} result
 * @param {number} result_offset offset into the result array
 * @param {number} result_stride
 * @param {number} p0
 * @param {number} p1
 * @param {number} p2
 * @param {number} p3
 */
export function spline3_bezier_bounds(result, result_offset, result_stride, p0, p1, p2, p3) {
    assert.greaterThan(result_stride, 0, 'result_stride must be greater than 0');
    assert.isInteger(result_stride, 'result_stride');

    const b = 6 * p0 - 12 * p1 + 6 * p2;
    const a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3;
    const c = 3 * p1 - 3 * p0;

    let min = min2(p0, p3);
    let max = max2(p0, p3);

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

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

            if (0 < t && t < 1) {
                const value = spline3_bezier(t, p0, p1, p2, p3);

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

            }

        }

    } else {

        const b2ac = b * b - 4 * c * a;
        const sqrtb2ac = Math.sqrt(b2ac);

        if (b2ac >= 0) {

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

            if (0 < t1 && t1 < 1) {
                const value = spline3_bezier(t1, p0, p1, p2, p3);

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

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

            if (0 < t2 && t2 < 1) {
                const value = spline3_bezier(t2, p0, p1, p2, p3);

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

        }

    }

    result[result_offset] = min;
    result[result_offset + result_stride] = max;
}

