// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// example_doc_random_samples.cpp
// Verification harness for samples in api/Random.html (ja+en).
// Documented values are the DETERMINISTIC ones (mean/variance/pdf/cdf/quantile,
// Halton points). Sample means use a fixed seed and are reported as approximate.

#include <math/random/random.hpp>
#include <math/random/distributions.hpp>
#include <math/random/quasi_random.hpp>
#include <iomanip>
#include <iostream>
#include <random>

using namespace sangi;

int main() {
    std::cout << std::setprecision(15);

    // ---- RandomEngine (reproducible) -----------------------------
    {
        std::cout << "[engine]\n";
        RandomEngine eng(42);
        double u = eng.uniform();          // [0,1)
        int d = eng.uniformInt(1, 6);      // dice
        RandomEngine eng2(42);
        bool reproducible = (eng2.uniform() == u);
        std::cout << "  uniform in [0,1)? " << (u >= 0.0 && u < 1.0) << "\n";
        std::cout << "  dice in [1,6]?   " << (d >= 1 && d <= 6) << "\n";
        std::cout << "  same seed reproducible? " << reproducible << "\n";
    }

    // ---- NormalDistribution (deterministic moments) --------------
    {
        std::cout << "[normal]\n";
        NormalDistribution<double> nd(0.0, 1.0);
        std::cout << "  mean      = " << nd.mean() << "\n";
        std::cout << "  variance  = " << nd.variance() << "\n";
        std::cout << "  pdf(0)    = " << nd.pdf(0.0) << "\n";
        std::cout << "  cdf(0)    = " << nd.cdf(0.0) << "\n";
        std::cout << "  q(0.975)  = " << nd.quantile(0.975) << "\n";
    }

    // ---- UniformDistribution -------------------------------------
    {
        std::cout << "[uniform-dist]\n";
        UniformDistribution<double> ud(0.0, 1.0);
        std::cout << "  mean      = " << ud.mean() << "\n";
        std::cout << "  variance  = " << ud.variance() << "\n";
        std::cout << "  pdf(0.5)  = " << ud.pdf(0.5) << "\n";
    }

    // ---- ExponentialDistribution ---------------------------------
    {
        std::cout << "[exponential]\n";
        ExponentialDistribution<double> ed(2.0);  // rate lambda = 2
        std::cout << "  mean      = " << ed.mean() << "\n";
        std::cout << "  variance  = " << ed.variance() << "\n";
    }

    // ---- discrete: Poisson, Binomial -----------------------------
    {
        std::cout << "[poisson]\n";
        PoissonDistribution<double> pd(3.0);
        std::cout << "  mean      = " << pd.mean() << "\n";
        std::cout << "  variance  = " << pd.variance() << "\n";

        std::cout << "[binomial]\n";
        BinomialDistribution<double> bd(10, 0.5);
        std::cout << "  mean      = " << bd.mean() << "\n";
        std::cout << "  variance  = " << bd.variance() << "\n";
        std::cout << "  pmf(5)    = " << bd.pmf(5) << "\n";
    }

    // ---- sampling: fixed-seed sample mean ~ true mean ------------
    {
        std::cout << "[sampling]\n";
        std::mt19937 gen(12345);
        NormalDistribution<double> nd(2.0, 0.5);
        double s = 0.0;
        const int N = 100000;
        for (int i = 0; i < N; ++i) s += nd.sample(gen);
        std::cout << "  sample mean (N=1e5) ~ " << (s / N) << "  (true 2.0)\n";
    }

    // ---- quasi-random: Halton (deterministic) --------------------
    {
        std::cout << "[halton]\n";
        HaltonSequence<2> h;           // bases (2, 3)
        for (int i = 0; i < 4; ++i) {
            auto p = h.next();
            std::cout << "  p" << i << " = (" << p[0] << ", " << p[1] << ")\n";
        }
    }

    return 0;
}
