import { v2_length } from "../../geom/vec2/v2_length.js";
import { find_cusp } from "./find_cusp.js";
import { linear_srgb_to_oklab } from "./linear_srgb_to_oklab.js";
import { oklab_to_linear_srgb } from "./oklab_to_linear_srgb.js";
import { toe, toe_inv } from "./toe.js";

const Lab = [0, 0, 0];

/**
 *
 * @type {number[]}
 */
const cusp = [0, 0];
/**
 *
 * @type {number[]}
 */
const rgb_scale = [0, 0, 0];

/**
 *
 * @param {number[]} output
 * @param {number} r
 * @param {number} g
 * @param {number} b
 */
export function linear_srgb_to_okhsv(output, r, g, b) {

    linear_srgb_to_oklab(Lab, r, g, b)

    let L = Lab[0];

    if(L === 0){
        // going to be all 0s
        output[0] = 0;
        output[1] = 0;
        output[2] = 0;
        return ;
    }

    let C = v2_length(Lab[1], Lab[2]);

    let a_ = Lab[1] / C;
    let b_ = Lab[2] / C;

    const h = 0.5 + 0.5 * Math.atan2(-Lab[2], -Lab[1]) / Math.PI;

    find_cusp(cusp, a_, b_);

    const S_max = cusp[1] / cusp[0];
    const T_max = cusp[1] / (1 - cusp[0]);

    const S_0 = 0.5;
    const k = 1 - S_0 / S_max;

    // first we find L_v, C_v, L_vt and C_vt

    const t = T_max / (C + L * T_max);
    const L_v = t * L;
    const C_v = t * C;

    const L_vt = toe_inv(L_v);
    const C_vt = C_v * L_vt / L_v;

    // we can then use these to invert the step that compensates for the toe and the curved top part of the triangle:

    oklab_to_linear_srgb(rgb_scale, L_vt, a_ * C_vt, b_ * C_vt);

    const scale_L = Math.cbrt(1. / Math.max(rgb_scale[0], rgb_scale[1], rgb_scale[2], 0));

    L = L / scale_L;
    C = C / scale_L;

    C = C * toe(L) / L;
    L = toe(L);

    // we can now compute v and s:

    const v = L / L_v;
    const s = (S_0 + T_max) * C_v / ((T_max * S_0) + T_max * k * C_v);

    output[0] = h;
    output[1] = s;
    output[2] = v;
}