#pragma once

#include "datascience/rng.h"
#include <cstddef>
#include <functional>

namespace fn::ds {

struct MHResult {
    std::size_t n_samples = 0;
    std::size_t n_accepted = 0;
    double accept_rate = 0.0;     // n_accepted / max(n_samples-1, 1)
};

// Metropolis-Hastings 1D con proposal Gaussian symmetric.
//
//   target_log_pdf(x): log-densidad target (no necesita normalizarse).
//   x0: punto inicial.
//   proposal_sigma: stddev del proposal (Gaussian centrada en current).
//   n_samples: cuantos samples generar (incluido x0).
//   out_chain: buffer destino double[n_samples].
//   r: estado RNG mutado in-place.
//
// El sample [0] es x0; [i] es la cadena tras i steps.
MHResult mh_run_1d(const std::function<double(double)>& target_log_pdf,
                   double x0,
                   double proposal_sigma,
                   std::size_t n_samples,
                   double* out_chain,
                   Rng& r);

// Metropolis-Hastings d-dimensional con proposal Gaussian symmetric (cada
// dim independiente con stddev proposal_sigma[d]). x0 y out_chain en
// layout row-major: out_chain[i*d + k] = sample i, dim k. proposal_sigma
// y x0 son arrays de tamano d.
MHResult mh_run_nd(const std::function<double(const double*)>& target_log_pdf,
                   const double* x0,
                   const double* proposal_sigma,
                   int d,
                   std::size_t n_samples,
                   double* out_chain,
                   Rng& r);

} // namespace fn::ds
