use strafe_type::{FloatConstraint, Natural64, Probability64, Real64};
use crate::{distribution::birthday::p::pbirthday, func::lgamma};
pub fn qbirthday<P: Into<Probability64>, N1: Into<Natural64> + Copy, N2: Into<Natural64> + Copy>(
prob: P,
classes: N1,
coincident: N2,
) -> Real64 {
let k = coincident.into().unwrap() as usize;
let c = classes.into().unwrap() as usize;
let p = prob.into().unwrap();
if p <= 0.0 {
return 1.0.into();
}
if p >= 1.0 {
return c.saturating_mul(k - 1).saturating_add(1).into();
}
let k = coincident.into().unwrap();
let c = classes.into().unwrap();
let mut N = (((k - 1.0) * c.ln() + lgamma(k + 1.0).unwrap() + (-(-p).ln_1p()).ln()) / k).exp();
N = N.ceil();
if pbirthday(N, classes, coincident).unwrap() < p {
N += 1.0;
while pbirthday(N, classes, coincident).unwrap() < p {
N += 1.0;
}
} else if pbirthday(N - 1.0, classes, coincident).unwrap() >= p {
N -= 1.0;
while pbirthday(N - 1.0, classes, coincident).unwrap() >= p {
N -= 1.0;
}
}
N.into()
}