/**
 * Finds the maximum saturation possible for a given hue that fits in sRGB
 * Saturation here is defined as S = C/L
 * a and b must be normalized so a^2 + b^2 == 1
 * @param {number} a
 * @param {number} b
 * @returns {number}
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export function compute_max_saturation(a, b) {
    // Max saturation will be when one of r, g or b goes below zero.

    // Select different coefficients depending on which component goes below zero first
    let k0, k1, k2, k3, k4, wl, wm, ws;

    if (-1.88170328 * a - 0.80936493 * b > 1) {
        // Red component
        k0 = +1.19086277;
        k1 = +1.76576728;
        k2 = +0.59662641;
        k3 = +0.75515197;
        k4 = +0.56771245;
        wl = +4.0767416621;
        wm = -3.3077115913;
        ws = +0.2309699292;
    } else if (1.81444104 * a - 1.19445276 * b > 1) {
        // Green component
        k0 = +0.73956515;
        k1 = -0.45954404;
        k2 = +0.08285427;
        k3 = +0.12541070;
        k4 = +0.14503204;
        wl = -1.2684380046;
        wm = +2.6097574011;
        ws = -0.3413193965;
    } else {
        // Blue component
        k0 = +1.35733652;
        k1 = -0.00915799;
        k2 = -1.15130210;
        k3 = -0.50559606;
        k4 = +0.00692167;
        wl = -0.0041960863;
        wm = -0.7034186147;
        ws = +1.7076147010;
    }

    // Approximate max saturation using a polynomial:
    let S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b;

    // Do one step of Halley's method to get closer
    // this gives an error less than 10e6, except for some blue hues where the dS/dh is close to infinite
    // this should be sufficient for most applications, otherwise do two/three steps

    const k_l = +0.3963377774 * a + 0.2158037573 * b;
    const k_m = -0.1055613458 * a - 0.0638541728 * b;
    const k_s = -0.0894841775 * a - 1.2914855480 * b;

    {
        const l_ = 1. + S * k_l;
        const m_ = 1. + S * k_m;
        const s_ = 1. + S * k_s;

        const l = l_ * l_ * l_;
        const m = m_ * m_ * m_;
        const s = s_ * s_ * s_;

        const l_dS = 3. * k_l * l_ * l_;
        const m_dS = 3. * k_m * m_ * m_;
        const s_dS = 3. * k_s * s_ * s_;

        const l_dS2 = 6. * k_l * k_l * l_;
        const m_dS2 = 6. * k_m * k_m * m_;
        const s_dS2 = 6. * k_s * k_s * s_;

        const f = wl * l + wm * m + ws * s;
        const f1 = wl * l_dS + wm * m_dS + ws * s_dS;
        const f2 = wl * l_dS2 + wm * m_dS2 + ws * s_dS2;

        S = S - f * f1 / (f1 * f1 - 0.5 * f * f2);
    }

    return S;
}