// Copyright (c) 2025 Adam Ulichny
//
// This source code is licensed under the MIT OR Apache-2.0 license
// that can be found in the LICENSE-MIT or LICENSE-APACHE files
// at the root of this source tree.

//! Test of the hypothesis that the sample data could have been generated by a pareto process.
//! Function to hypothesis test the best fit params to m synthetic datasets. This is Section 4 of
//! Clauset, Aaron and Shalizi, Cosma Rohilla and Newman, M. E. J. [doi:10.48550/ARXIV.0706.1062](https://doi.org/10.48550/arXiv.0706.1062)
use super::estimation::find_alphas_fast;
use super::gof::{gof, Fitment};
use crate::util::sim::{self, SimParams};

pub struct H0 {
    pub gt: usize,
    pub total: usize,
    pub p: f64,
}

pub fn hypothesis_test(data: Vec<f64>, prec: f64, alpha: f64, x_min: f64, best_d: f64) -> H0 {
    /*
    Parameters
    ----------
    data: Vec<f64>
        sample dataset to fit on
    prec: f64
        precision of the estimate ex 1/4 * prec^(-2). Ex. 1/4 * 0.01^(-2) = 2500 sims gives accuracy within 0.01
    alpha: f64
        alpha of proposed best fit
    x_min: f64
        x_min of proposed best fit
    best_d: f64
        This is the KS test D value from the alpha/x_min combo that had the best fit.

    Returns:
    ----------
    */

    // setup the simulation: number of sims, elements in each etc.
    let sim_params: SimParams = sim::calculate_sim_params(&prec, &data, &x_min);
    //let (M, n, n_tail, p_tail) = sim_params;

    println!("{:?}", sim_params);

    let S: Vec<Vec<f64>> = sim::generate_synthetic_datasets(&data, x_min, sim_params, alpha);
    let sim_size: usize = S.len();

    // loop through each sim and calculate the KS d value
    let mut sim_ds = vec![];

    for mut i in S {
        //let start = Instant::now(); // Record the start time
        // Step 1: test finding the MLE alphas for a given range of x_min and the data
        let alphas: (Vec<f64>, Vec<f64>) = find_alphas_fast(&mut i);

        //let alphas: (Vec<f64>, Vec<f64>) = find_alphas_fast(r, & mut i);
        // Step 2: gof KS test the cdf of the proposed x_min and alpha hat vs the sample with x >= x_min.
        // this is to find the best x_min/alpha pair given the data
        let best_fit: Fitment = gof(&i, &alphas.0, &alphas.1);
        //println!("best fit {:?}", best_fit);
        sim_ds.push(best_fit.D);
        //println!("Best fit D {d}");
        //let duration = start.elapsed(); // Calculate the elapsed time
        //println!("loop took: {:.2?} seconds", duration);
    }

    let gt = sim_ds.iter().filter(|&x| *x > best_d).count();
    //let n = final_sim.len();

    //let p = gt as f64 / n as f64;
    //println!("gt {gt} n {n} p is: {p}");

    let p = gt as f64 / sim_size as f64;
    //println!("gt {gt} n {sim_size} p is: {p}");
    //(gt, sim_size, p)
    H0 {
        gt: gt,
        total: sim_size,
        p: p,
    }
}
