const scratch_mat_5x5 = new Float64Array(25);

/**
 * Rotate spherical harmonics
 * @param {number[]|Float32Array} result sh3
 * @param {number[]} sh input
 * @param {number[]} rotation 3x3 rotation matrix
 */
export function sh3_rotate_bl(result, sh, rotation) {
    // Implementation adapted from BakerLab by https://github.com/TheRealMJP

    const r00 = rotation[0];
    const r10 = rotation[1];
    const r20 = rotation[2];

    const r01 = rotation[3];
    const r11 = rotation[4];
    const r21 = rotation[5];

    const r02 = rotation[6];
    const r12 = rotation[7];
    const r22 = rotation[8];


    // band-0 : Constant
    result[0] = sh[0];

    // band-1: Linear
    result[1] = r11 * sh[1] - r12 * sh[2] + r10 * sh[3];
    result[2] = -r21 * sh[1] + r22 * sh[2] - r20 * sh[3];
    result[3] = r01 * sh[1] - r02 * sh[2] + r00 * sh[3];

    // band-2: Quadratic
    const t41 = r01 * r00;
    const t43 = r11 * r10;
    const t48 = r11 * r12;
    const t50 = r01 * r02;
    const t55 = r02 * r02;
    const t57 = r22 * r22;
    const t58 = r12 * r12;
    const t61 = r00 * r02;
    const t63 = r10 * r12;
    const t68 = r10 * r10;
    const t70 = r01 * r01;
    const t72 = r11 * r11;
    const t74 = r00 * r00;
    const t76 = r21 * r21;
    const t78 = r20 * r20;

    const v173 = 0.1732050808e1;
    const v577 = 0.5773502693e0;
    const v115 = 0.1154700539e1;
    const v288 = 0.2886751347e0;
    const v866 = 0.8660254040e0;

    scratch_mat_5x5[0] = r11 * r00 + r01 * r10;
    scratch_mat_5x5[1] = -r01 * r12 - r11 * r02;
    scratch_mat_5x5[2] = v173 * r02 * r12;
    scratch_mat_5x5[3] = -r10 * r02 - r00 * r12;
    scratch_mat_5x5[4] = r00 * r10 - r01 * r11;
    scratch_mat_5x5[5] = -r11 * r20 - r21 * r10;
    scratch_mat_5x5[6] = r11 * r22 + r21 * r12;
    scratch_mat_5x5[7] = -v173 * r22 * r12;
    scratch_mat_5x5[8] = r20 * r12 + r10 * r22;
    scratch_mat_5x5[9] = -r10 * r20 + r11 * r21;
    scratch_mat_5x5[10] = -v577 * (t41 + t43) + v115 * r21 * r20;
    scratch_mat_5x5[11] = v577 * (t48 + t50) - v115 * r21 * r22;
    scratch_mat_5x5[12] = -0.5 * (t55 + t58) + t57;
    scratch_mat_5x5[13] = v577 * (t61 + t63) - v115 * r20 * r22;
    scratch_mat_5x5[14] = v288 * (t70 - t68 + t72 - t74) - v577 * (t76 - t78);
    scratch_mat_5x5[15] = -r01 * r20 - r21 * r00;
    scratch_mat_5x5[16] = r01 * r22 + r21 * r02;
    scratch_mat_5x5[17] = -v173 * r22 * r02;
    scratch_mat_5x5[18] = r00 * r22 + r20 * r02;
    scratch_mat_5x5[19] = -r00 * r20 + r01 * r21;
    scratch_mat_5x5[20] = t41 - t43;
    scratch_mat_5x5[21] = -t50 + t48;
    scratch_mat_5x5[22] = v866 * (t55 - t58);
    scratch_mat_5x5[23] = t63 - t61;
    scratch_mat_5x5[24] = 0.5 * (t74 - t68 - t70 + t72);

    for (let i = 0; i < 5; ++i) {
        const base = i * 5;

        result[4 + i] = scratch_mat_5x5[base + 0] * sh[4]
            + scratch_mat_5x5[base + 1] * sh[5]
            + scratch_mat_5x5[base + 2] * sh[6]
            + scratch_mat_5x5[base + 3] * sh[7]
            + scratch_mat_5x5[base + 4] * sh[8]
        ;
    }

    return result;
}