// ---------------- [ File: tktax-stats/src/txn_summary_stats.rs ]
crate::ix!();

pub fn print_categorized_transaction_summary_statistics(txns: &[&Transaction]) {

    match TxSummaryStatistics::create_if_nonempty(txns) {
        Some(stats) => println!("{}", stats),
        None        => {}
    }
}

//---------------------------------------
#[derive(Getters,Clone,Debug)]
#[getset(get="pub")]
pub struct TxSummaryStatistics {
    count:                usize,
    min:                  MonetaryAmount,
    max:                  MonetaryAmount,
    midrange:             MonetaryAmount,
    average:              MonetaryAmount,
    median:               MonetaryAmount,
    repeated:             Vec<(MonetaryAmount,usize)>,
    standard_deviation:   MonetaryAmount,
    quartiles_iqr:        MoneyQuartiles,
    outliers_iqr:         Vec<MonetaryAmount>,
    skewness:             Dimensionless,
    kurtosis:             Dimensionless,
    cumulative_frequency: Vec<MonetaryAmount>,
}

impl fmt::Display for TxSummaryStatistics {

    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

        const DO_CUMULATIVE_FREQUENCY: bool = false;
        const DO_REPEATED:             bool = true;
        const DO_QUARTILES_IQR:        bool = true;
        const DO_OUTLIERS_IQR:         bool = true;

        writeln!(f, "~ ------------[summary stats]------------ ~")?;

        writeln!(f, "count:                {:?}", self.count)?;
        writeln!(f, "min:                  {:?}", self.min)?;
        writeln!(f, "max:                  {:?}", self.max)?;
        writeln!(f, "avg:                  {:?}", self.average)?;
        writeln!(f, "midrange:             {:?}", self.midrange)?;
        writeln!(f, "median:               {:?}", self.median)?;
        writeln!(f, "standard dev:         {:?}", self.standard_deviation)?;
        writeln!(f, "skewness:             {}",   self.skewness)?;
        writeln!(f, "kurtosis:             {}",   self.kurtosis)?;

        if DO_REPEATED {
            if self.repeated.is_empty() {
                writeln!(f, "<no repeated transaction amounts>")?;
            } else {
                writeln!(f, "repeated:")?;
                for item in self.repeated.iter() {
                    writeln!(f, "  {:<3}@{}", item.1, item.0)?;
                }
                //writeln!(f,"")?;
            }
        }

        if DO_QUARTILES_IQR {
            writeln!(f, "quartiles_iqr:")?;
            writeln!(f, "  {}", self.quartiles_iqr.0)?;
            writeln!(f, "  {}", self.quartiles_iqr.1)?;
            writeln!(f, "  {}", self.quartiles_iqr.2)?;
            writeln!(f, "  {}", self.quartiles_iqr.3)?;
            writeln!(f,"")?;
        }

        if DO_OUTLIERS_IQR {
            if self.outliers_iqr.is_empty() {
                writeln!(f, "<no iqr outliers detected>")?;
            } else {
                writeln!(f, "outliers_iqr:")?;
                for item in self.outliers_iqr.iter() {
                    writeln!(f, "  {}", item)?;
                }
                //writeln!(f,"")?;
            }
        }

        if DO_CUMULATIVE_FREQUENCY {
            assert!(!self.cumulative_frequency.is_empty());
            writeln!(f, "cumulative_frequency:")?;
            for item in self.cumulative_frequency.iter() {
                writeln!(f, "  {}", item)?;
            }
            //writeln!(f,"")?;
        }

        Ok(())
    }
}

impl TxSummaryStatistics {

    pub fn create_if_nonempty(txns: &[&Transaction]) -> Option<Self> {

        if txns.is_empty() {
            return None;
        }

        let amounts: Vec<MonetaryAmount> = txns.iter().map(|tx| tx.amount()).collect();

        Some(Self {
            count:                amounts.len(),
            min:                  amounts.min_value().ok()?,
            max:                  amounts.max_value().ok()?,
            midrange:             amounts.midrange().ok()?,
            average:              amounts.mean().ok()?,
            median:               amounts.median().ok()?,
            repeated:             amounts.repeated_values().ok()?,
            standard_deviation:   amounts.stddev().ok()?,
            quartiles_iqr:        amounts.quartiles_iqr().ok()?,
            outliers_iqr:         amounts.outliers_iqr().ok()?,
            skewness:             amounts.skewness().ok()?,
            kurtosis:             amounts.kurtosis().ok()?,
            cumulative_frequency: amounts.cumulative_frequency().ok()?,
        })
    }
}
