import { sh3_basis_at } from "../../../core/geom/3d/sphere/harmonics/sh3_basis_at.js";
import { sh3_dering_optimize_positive } from "../../../core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js";
import { sh3_vector_accumulate } from "../../../core/geom/3d/sphere/harmonics/sh3_vector_accumulate.js";
import { vector_scale_array } from "../../../core/geom/vec/vector_scale_array.js";
import { v3_length_sqr } from "../../../core/geom/vec3/v3_length_sqr.js";

const scratch_color = new Float32Array(3);

/**
 *
 * @param {Uint8Array} data
 * @param {THREE.WebGLRenderer} renderer
 * @param {THREE.WebGLCubeRenderTarget} cubeRenderTarget
 * @return {Float64Array}
 */
export function fromCubeRenderTarget(
    data,
    renderer,
    cubeRenderTarget
) {

    // The renderTarget must be set to RGBA in order to make readRenderTargetPixels works
    let total_weight = 0;

    const __shared_buffer = new ArrayBuffer((27 + 9) * 8);

    const sh_basis = new Float64Array(__shared_buffer, 0, 9);
    const coefficients = new Float64Array(__shared_buffer, 9 * 8, 27);

    const image_size = cubeRenderTarget.width;

    const pixel_size = 2 / image_size;

    let normal_x = 0, normal_y = 0, normal_z = 0;

    for (let faceIndex = 0; faceIndex < 6; faceIndex++) {

        renderer.readRenderTargetPixels(cubeRenderTarget, 0, 0, image_size, image_size, data, faceIndex);

        // RGBA assumed

        for (let i = 0, il = data.length; i < il; i += 4) {


            // pixel coordinate on unit cube

            const pixelIndex = i / 4;

            const col = -1 + (pixelIndex % image_size + 0.5) * pixel_size;

            const row = 1 - (Math.floor(pixelIndex / image_size) + 0.5) * pixel_size;


            switch (faceIndex) {

                case 0:
                    normal_x = 1;
                    normal_y = row;
                    normal_z = -col;
                    break;

                case 1:
                    normal_x = -1;
                    normal_y = row;
                    normal_z = col;
                    break;

                case 2:
                    normal_x = col;
                    normal_y = 1;
                    normal_z = -row;
                    break;

                case 3:
                    normal_x = col;
                    normal_y = -1;
                    normal_z = row;
                    break;

                case 4:
                    normal_x = col;
                    normal_y = row;
                    normal_z = 1;
                    break;

                case 5:
                    normal_x = -col;
                    normal_y = row;
                    normal_z = -1;
                    break;

            }

            // weight assigned to this pixel

            const length_squared = v3_length_sqr(normal_x, normal_y, normal_z);

            const length = Math.sqrt(length_squared);

            const weight = 4 / (length * length_squared);

            total_weight += weight;

            // direction vector to this pixel
            normal_x /= length;
            normal_y /= length;
            normal_z /= length;

            // evaluate SH basis functions in direction dir
            sh3_basis_at(normal_x, normal_y, normal_z, sh_basis);

            // pixel color, already in linear space so no sRGB->Linear conversion necessary

            // 0.003921 constant value is 1/255, a conversion value from UINT8 to normalized float
            const weight_conv = weight * 0.00392156862745098;

            scratch_color[0] = data[i] * weight_conv;
            scratch_color[1] = data[i + 1] * weight_conv;
            scratch_color[2] = data[i + 2] * weight_conv;

            // accumulate
            sh3_vector_accumulate(
                coefficients, 0,
                sh_basis, 0,
                scratch_color, 0,
                3
            );

        }

    }

    // normalize
    const norm = (4 * Math.PI) / total_weight;

    vector_scale_array(coefficients, 0, coefficients, 0, 27, norm);

    sh3_dering_optimize_positive(coefficients, 0, coefficients, 0, 3);

    return coefficients;

}