use rand::Rng;
use chrono::{DateTime, TimeZone, Utc};
use std::num::ParseIntError;
pub fn get_noise() -> String {
let mut rng = rand::thread_rng();
let counter: u16 = rng.gen_range(0..=u16::MAX);
format!("{:02x}", counter)
}
pub fn parse_aid(aid: &str) -> Result<DateTime<Utc>, Box<dyn std::error::Error>> {
let base36_time = &aid[..8];
let time_milliseconds = b36_decode(base36_time)?;
let timestamp = 946684800 + time_milliseconds / 1000;
Utc.timestamp_opt(timestamp as i64, 0)
.single()
.ok_or_else(|| "Invalid timestamp".into())
}
pub fn gen_aid() -> String {
let current = ((chrono::Utc::now().timestamp() + 946684800) * 1000) as u64;
let base36_time = b36_encode(current);
let noise = get_noise();
format!("{:0>8}{}", base36_time, noise)
}
pub fn gen_aidx() -> String {
let current_time = ((chrono::Utc::now().timestamp() + 946684800) * 1000) as u64;
let base36_time = b36_encode(current_time);
let individual_id = format!("{:04X}", rand::thread_rng().gen_range(0..=u16::MAX));
let counter = format!("{:04X}", rand::thread_rng().gen_range(0..=u16::MAX));
format!("{:0>8}{}{}", base36_time, individual_id, counter)
}
pub fn parse_aidx(aidx: &str) -> Result<DateTime<Utc>, Box<dyn std::error::Error>> {
let base36_time = &aidx[..8];
let time_milliseconds = b36_decode(base36_time)?;
let timestamp = 946684800 + time_milliseconds / 1000;
Utc.timestamp_opt(timestamp as i64, 0)
.single()
.ok_or_else(|| "Invalid timestamp".into())
}
fn b36_encode(mut number: u64) -> String {
let alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
let mut base36 = String::new();
while number > 0 {
let (quotient, remainder) = (number / 36, number % 36);
base36.insert(0, alphabet.chars().nth(remainder as usize).unwrap());
number = quotient;
}
if base36.is_empty() {
base36.push(alphabet.chars().nth(0).unwrap());
}
base36
}
fn b36_decode(number: &str) -> Result<u64, ParseIntError> {
u64::from_str_radix(number, 36)
}