import { v3_length } from "../../vec3/v3_length.js";

/**
 *
 * @param {number[]|ArrayLike<number>|Float32Array} output 7 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z, tMax]
 * @param {number} output_offset
 * @param {number[]|ArrayLike<number>|Float32Array} input 7 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z, tMax]
 * @param {number} input_offset
 * @param {number[]|ArrayLike<number>|Float32Array} m4 4x4 matrix
 * @returns {boolean} false if matrix transformation is impossible, such as when scale of the matrix is 0
 */
export function ray3_interval_array_apply_matrix4(
    output, output_offset,
    input, input_offset,
    m4
) {
    const origin_x = input[input_offset + 0];
    const origin_y = input[input_offset + 1];
    const origin_z = input[input_offset + 2];

    const direction_x = input[input_offset + 3];
    const direction_y = input[input_offset + 4];
    const direction_z = input[input_offset + 5];

    const t_max = input[input_offset + 6];


    const in_min_x = origin_x ;
    const in_min_y = origin_y ;
    const in_min_z = origin_z ;

    const in_max_x = origin_x + direction_x * t_max;
    const in_max_y = origin_y + direction_y * t_max;
    const in_max_z = origin_z + direction_z * t_max;

    // transform ray to local space (inlined for speed)
    const w0 = m4[3] * in_min_x + m4[7] * in_min_y + m4[11] * in_min_z + m4[15];

    const inv_w0 = 1 / w0;

    const out_min_x = (m4[0] * in_min_x + m4[4] * in_min_y + m4[8] * in_min_z + m4[12]) * inv_w0;
    const out_min_y = (m4[1] * in_min_x + m4[5] * in_min_y + m4[9] * in_min_z + m4[13]) * inv_w0;
    const out_min_z = (m4[2] * in_min_x + m4[6] * in_min_y + m4[10] * in_min_z + m4[14]) * inv_w0;

    // transform ray to local space (inlined for speed)
    const w1 = m4[3] * in_max_x + m4[7] * in_max_y + m4[11] * in_max_z + m4[15];

    const inv_w1 = 1 / w1;

    const out_max_x = (m4[0] * in_max_x + m4[4] * in_max_y + m4[8] * in_max_z + m4[12]) * inv_w1;
    const out_max_y = (m4[1] * in_max_x + m4[5] * in_max_y + m4[9] * in_max_z + m4[13]) * inv_w1;
    const out_max_z = (m4[2] * in_max_x + m4[6] * in_max_y + m4[10] * in_max_z + m4[14]) * inv_w1;

    const delta_x = out_max_x - out_min_x;
    const delta_y = out_max_y - out_min_y;
    const delta_z = out_max_z - out_min_z;

    // normalize direction
    const out_direction_magnitude = v3_length(delta_x, delta_y, delta_z);

    const out_direction_magnitude_inverse = 1 / out_direction_magnitude;

    const out_direction_normalized_x = delta_x * out_direction_magnitude_inverse;
    const out_direction_normalized_y = delta_y * out_direction_magnitude_inverse;
    const out_direction_normalized_z = delta_z * out_direction_magnitude_inverse;

    output[output_offset + 0] = out_min_x;
    output[output_offset + 1] = out_min_y;
    output[output_offset + 2] = out_min_z;

    output[output_offset + 3] = out_direction_normalized_x;
    output[output_offset + 4] = out_direction_normalized_y;
    output[output_offset + 5] = out_direction_normalized_z;

    output[output_offset + 6] = out_direction_magnitude;

    return true;
}