use std::string::FromUtf8Error;
use rand::RngExt;
use rand::distr::Distribution;
use semver::{BuildMetadata, Prerelease};
pub(crate) const SEMVER_REGEX: &str = r"^(?-u:(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)$";
pub(crate) const ALWAYS_PRERELEASE_REGEX: &str = r"(?-u:(?:((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)))";
pub(crate) const ALWAYS_BUILD_METADATA_REGEX: &str =
r"(?-u:(?:([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)))";
pub(crate) const DEFAULT_MAX_REPEAT: u32 = 100;
pub(crate) fn generate_any_valid_semver(count: usize) -> Vec<String> {
let mut rng = rand::rng();
let semver =
rand_regex::Regex::compile(&SEMVER_REGEX[1..SEMVER_REGEX.len() - 1], DEFAULT_MAX_REPEAT)
.unwrap();
(&mut rng)
.sample_iter(semver)
.take(count)
.collect::<Vec<String>>()
}
pub(crate) fn generate_u64_safe_semver(count: usize) -> Vec<String> {
type RandomStringRegexIter =
rand::distr::Iter<rand_regex::Regex, rand::rngs::ThreadRng, Result<String, FromUtf8Error>>;
let mut rng = rand::rng();
let pre_release_gen: RandomStringRegexIter =
rand_regex::Regex::compile(ALWAYS_PRERELEASE_REGEX, DEFAULT_MAX_REPEAT)
.unwrap()
.sample_iter(rand::rng());
let build_metadata_gen: RandomStringRegexIter =
rand_regex::Regex::compile(ALWAYS_BUILD_METADATA_REGEX, DEFAULT_MAX_REPEAT)
.unwrap()
.sample_iter(rand::rng());
pre_release_gen
.zip(build_metadata_gen)
.map(|(pr, bm)| {
format!(
"{}.{}.{}{}{}",
rng.random::<u64>(),
rng.random::<u64>(),
rng.random::<u64>(),
match rng.random_bool(0.5) {
true => format!("-{}", Prerelease::new(&pr.unwrap()).unwrap()),
_ => "".to_string(),
},
match rng.random_bool(0.5) {
true => format!("+{}", BuildMetadata::new(&bm.unwrap()).unwrap()),
_ => "".to_string(),
}
)
})
.take(count)
.collect::<Vec<String>>()
}