import { find_cusp } from "./find_cusp.js";
import { oklab_to_linear_srgb } from "./oklab_to_linear_srgb.js";
import { toe_inv } from "./toe.js";

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

/**
 * @param {number[]} output
 * @param {number} h
 * @param {number} s
 * @param {number} v
 *
 * @author Alex Goldring
 * @copyright Company Named Limited (c) 2026
 */
export function okhsv_to_linear_srgb(output, h, s, v) {

    const a_ = Math.cos(2 * Math.PI * h);
    const b_ = Math.sin(2 * Math.PI * h);

    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 compute L and V as if the gamut is a perfect triangle:

    // L, C when v==1:
    const L_v = 1 - s * S_0 / (S_0 + T_max - T_max * k * s);
    const C_v = s * T_max * S_0 / (S_0 + T_max - T_max * k * s);

    let L = v * L_v;
    let C = v * C_v;

    // then we compensate for both toe and the curved top part of the triangle:
    const L_vt = toe_inv(L_v);
    const C_vt = C_v * L_vt / L_v;

    const L_new = toe_inv(L);

    if(L !== 0) {
        C = C * L_new / L;
    }else{
        // avoid division by 0
        C = 0;
    }

    L = L_new;

    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;

    oklab_to_linear_srgb(output, L, C * a_, C * b_);
}