#pragma once

#include "gfx/gpu_ssbo.h"
#include <string>

namespace fn::ds {

// Random walk 2D MH para mcmc-visualizer. Cada thread es un walker
// independiente; cada step propone (x, y) -> (x + N(0,sigma), y + N(0,sigma))
// y acepta con prob min(1, exp(log_pdf_prop - log_pdf_curr)).
//
// Output:
//   trace_xy[m_walkers * n_steps_per_run * 2] floats — trayectoria
//                                                       (x, y, x, y, ...)
//   accept_counts[m_walkers] uints
//
// Para alimentar heatmap directamente, usar la trayectoria con
// gpu_histogram_2d (mismo binding pattern: float[2*N]).
struct McRandomWalk2DGpu {
    unsigned int program = 0;

    fn::gfx::Ssbo trace_xy;
    fn::gfx::Ssbo accept_counts;
    fn::gfx::Ssbo curr_xy;        // float[2 * m_walkers]
    fn::gfx::Ssbo rng_seeds;

    int m_walkers = 0;
    int n_steps_per_run = 0;

    unsigned int loc_n_walkers = 0;
    unsigned int loc_n_steps   = 0;
    unsigned int loc_sigma     = 0;
};

// target_log_pdf_glsl debe definir
//   float target_log_pdf(vec2 p) { ... }
// y puede leer u_user[16].
McRandomWalk2DGpu mc_rw2d_gpu_create(int m_walkers, int n_steps_per_run,
                                     const std::string& target_log_pdf_glsl);

// Resetea seeds y curr_xy a x0 (mismo punto para todos los walkers, o
// initial_xys != nullptr para arranque disperso).
void mc_rw2d_gpu_reset(McRandomWalk2DGpu& s,
                       unsigned long long master_seed,
                       float x0, float y0,
                       const float* initial_xys = nullptr);

void mc_rw2d_gpu_run(McRandomWalk2DGpu& s,
                     float proposal_sigma,
                     const float* user_params = nullptr,
                     int n_user_params = 0);

void mc_rw2d_gpu_readback_trace(const McRandomWalk2DGpu& s, float* out);
void mc_rw2d_gpu_readback_accepts(const McRandomWalk2DGpu& s,
                                  unsigned int* out);

// Acceso al SSBO de trace para encadenarlo directamente con
// gpu_histogram_2d sin readback. count = m_walkers * n_steps_per_run.
const fn::gfx::Ssbo& mc_rw2d_gpu_trace_ssbo(const McRandomWalk2DGpu& s);

void mc_rw2d_gpu_destroy(McRandomWalk2DGpu& s);

} // namespace fn::ds
