import { min3 } from "../../math/min3.js";
import { find_cusp } from "./find_cusp.js";

const cusp = [0, 0];

/**
 * Finds intersection of the line defined by
 * L = L0 * (1 - t) + t * L1;
 * C = t * C1;
 * a and b must be normalized so a^2 + b^2 == 1
 * @param {number} a
 * @param {number} b
 * @param {number} L1
 * @param {number} C1
 * @param {number} L0
 * @returns {number}
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export function find_gamut_intersection(a, b, L1, C1, L0) {
    // Find the cusp of the gamut triangle
    find_cusp(cusp, a, b);

    // Find the intersection for upper and lower half separately
    let t;
    if (((L1 - L0) * cusp[1] - (cusp[0] - L0) * C1) <= 0.) {
        // Lower half

        t = cusp[1] * L0 / (C1 * cusp[0] + cusp[1] * (L0 - L1));
    } else {
        // Upper half

        // First intersect with triangle
        t = cusp[1] * (L0 - 1.) / (C1 * (cusp[0] - 1.) + cusp[1] * (L0 - L1));

        // Then one step of Halley's method
        {
            const dL = L1 - L0;
            const dC = C1;

            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_dt = dL + dC * k_l;
            const m_dt = dL + dC * k_m;
            const s_dt = dL + dC * k_s;


            // If higher accuracy is required, 2 or 3 iterations of the following block can be used:
            {
                const L = L0 * (1 - t) + t * L1;
                const C = t * C1;

                const l_ = L + C * k_l;
                const m_ = L + C * k_m;
                const s_ = L + C * k_s;

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

                const ldt = 3 * l_dt * l_ * l_;
                const mdt = 3 * m_dt * m_ * m_;
                const sdt = 3 * s_dt * s_ * s_;

                const ldt2 = 6 * l_dt * l_dt * l_;
                const mdt2 = 6 * m_dt * m_dt * m_;
                const sdt2 = 6 * s_dt * s_dt * s_;

                const r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s - 1;
                const r1 = 4.0767416621 * ldt - 3.3077115913 * mdt + 0.2309699292 * sdt;
                const r2 = 4.0767416621 * ldt2 - 3.3077115913 * mdt2 + 0.2309699292 * sdt2;

                const u_r = r1 / (r1 * r1 - 0.5 * r * r2);
                let t_r = -r * u_r;

                const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s - 1;
                const g1 = -1.2684380046 * ldt + 2.6097574011 * mdt - 0.3413193965 * sdt;
                const g2 = -1.2684380046 * ldt2 + 2.6097574011 * mdt2 - 0.3413193965 * sdt2;

                const u_g = g1 / (g1 * g1 - 0.5 * g * g2);
                let t_g = -g * u_g;

                const b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s - 1;
                const b1 = -0.0041960863 * ldt - 0.7034186147 * mdt + 1.7076147010 * sdt;
                const b2 = -0.0041960863 * ldt2 - 0.7034186147 * mdt2 + 1.7076147010 * sdt2;

                const u_b = b1 / (b1 * b1 - 0.5 * b * b2);
                let t_b = -b * u_b;

                t_r = u_r >= 0 ? t_r : Number.MAX_VALUE;
                t_g = u_g >= 0 ? t_g : Number.MAX_VALUE;
                t_b = u_b >= 0 ? t_b : Number.MAX_VALUE;

                t += min3(t_r, t_g, t_b);
            }
        }
    }

    return t;
}