#pragma once

#include "gfx/gpu_ssbo.h"

namespace fn::gfx {

enum class ReduceOp : int {
    Sum = 0,
    Min = 1,
    Max = 2
};

// Reductor paralelo sobre SSBO float[N]. Usa workgroup-shared reduction.
// El reductor mantiene un SSBO intermedio para guardar los partials por
// workgroup (1 partial por workgroup). Tras dispatch, el ultimo paso es
// una reduccion CPU-side de los partials (count tipico: N/256 — barato).
//
// Para distintos N hay que destruir y recrear (el partials_capacity esta
// dimensionado al peor N pasado al constructor).
struct GpuReduce {
    unsigned int p_sum = 0;
    unsigned int p_min = 0;
    unsigned int p_max = 0;
    unsigned int loc_count = 0;
    unsigned int loc_count_min = 0;
    unsigned int loc_count_max = 0;
    Ssbo partials;        // float[max_groups]
    int max_groups = 0;
};

// max_n_samples: cota maxima del N que se reducira (dimensiona el partials).
// El local_size esta fijado a 256 internamente (workgroup tipico para
// shared-mem reduction en consumer GPUs).
GpuReduce gpu_reduce_create(int max_n_samples);

// Ejecuta reduce con la operacion indicada. Devuelve el resultado escalar.
// Bloquea (incluye readback de partials).
//
// samples: SSBO float[count] (binding 0 dentro del shader).
// count: cuantos samples efectivos procesar (<= max_n_samples).
float gpu_reduce_run(GpuReduce& r, ReduceOp op,
                     const Ssbo& samples, int count);

// Mean = sum / count. Helper que llama Sum y divide.
float gpu_reduce_mean(GpuReduce& r, const Ssbo& samples, int count);

void gpu_reduce_destroy(GpuReduce& r);

} // namespace fn::gfx
