use rand::distr::{Distribution, Uniform};
use std::io::Write;

pub fn flush() -> Result<(), std::io::Error> {
    std::io::stdout().flush()?;
    Ok(())
}

pub fn input() -> Result<String, std::io::Error> {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input)?;
    Ok(input.trim().to_string())
}

pub fn input_prompt(prompt: impl AsRef<str>) -> Result<String, std::io::Error> {
    print!("{}", prompt.as_ref());
    flush()?;
    let input = input()?;
    Ok(input)
}

pub fn randint<T>(x: T, y: T) -> T
where
    T: rand::distr::uniform::SampleUniform + PartialOrd + Copy,
{
    let range = Uniform::new_inclusive(x, y).unwrap();
    let mut rng = rand::rng();
    range.sample(&mut rng)
}

pub fn sort<T: PartialOrd + Clone>(arr: &[T]) -> Vec<T> {
    let mut result = arr.to_vec();
    let len = result.len();
    for i in 0..len {
        for j in 0..len - i - 1 {
            if result[j] > result[j + 1] {
                result.swap(j, j + 1);
            }
        }
    }
    result
}

pub fn time() -> f64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .expect("时间错误")
        .as_millis() as f64 / 1000.0
}


pub fn sleep(second: f64) {
    std::thread::sleep(std::time::Duration::from_secs_f64(second));
}

pub fn exit(exitcode: i32) {
    std::process::exit(exitcode);
}

pub fn getenv() -> std::collections::HashMap<String, String> {
    std::env::vars().collect()
}

pub fn clear() -> Result<(), std::io::Error> {
    print!("\x1B[2J\x1B[1;1H");
    std::io::stdout().flush()?;
    Ok(())
}

pub fn shell(cmd: &str) -> Result<String, Box<dyn std::error::Error>> {
    let output = subprocess::Exec::shell(cmd)
        .stdout(subprocess::Redirection::Pipe)
        .stderr(subprocess::Redirection::Pipe)
        .capture()?;

    Ok(String::from_utf8_lossy(&output.stdout).to_string())
}

#[macro_export]
macro_rules! pass {
    ($($expr:expr),+ $(,)?) => {
        $(
            let _ = &$expr;
        )*
    };
}
