import { build_gaussian_kernel_1d } from "../../../../../core/math/build_gaussian_kernel_1d.js";
import { max2 } from "../../../../../core/math/max2.js";
import { nextOdd } from "../../../../../core/math/nextOdd.js";
import { Sampler2D } from "../Sampler2D.js";


let temp_data = new Float64Array(1);

/**
 *
 * @param {Sampler2D} output
 * @param {Sampler2D} input
 * @param {number} size
 * @param {number} [quality]
 */
export function sampler2d_blur_gaussian(output, input, size, quality = 1) {

    const sigma = size * 3;
    const sample_count = max2(3, nextOdd(Math.round(size * quality)));

    const kernel = new Float32Array(sample_count);

    build_gaussian_kernel_1d(kernel, sample_count, sigma);

    const width = input.width;
    const height = input.height;
    const channel_count = input.itemSize;

    const total_value_count = width * height * channel_count;
    if (temp_data.length < total_value_count) {
        // our static temp buffer is too small, let's make it larger
        temp_data = new Float64Array(total_value_count);
    }

    let source = input;
    let target = new Sampler2D(temp_data, channel_count, width, height);

    const half_samples = (sample_count - 1) * 0.5;
    const local_u_scale = size / (sample_count - 1);
    const local_v_scale = size / (sample_count - 1);

    const sample = new Float64Array(channel_count);

    // horizonal pass
    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            sample.fill(0)

            for (let ix = 0; ix < sample_count; ix++) {

                const local_x = ix - half_samples;

                const sample_x = x + local_x * local_u_scale;

                const power = kernel[ix];

                for (let i = 0; i < channel_count; i++) {
                    const channel_value = source.sampleChannelBilinear(sample_x, y, i);

                    sample[i] += channel_value * power;
                }

            }

            target.write(x, y, sample);
        }
    }

    source = target;
    target = output;

    // vertical pass
    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            sample.fill(0)

            for (let iy = 0; iy < sample_count; iy++) {

                const local_y = iy - half_samples;

                const sample_y = y + local_y * local_v_scale;

                const power = kernel[iy];

                for (let i = 0; i < channel_count; i++) {
                    const channel_value = source.sampleChannelBilinear(x, sample_y, i);

                    sample[i] += channel_value * power;
                }

            }

            target.write(x, y, sample);
        }
    }


}