use chrono::Datelike;

// use std::ops::Add;

pub trait DateTimeExt {
    /// %Y-%m-%d %H:%M:%S%.3f
    /// "{year}-{month}-{day} {hour}:{minute}:{second}.{milisecond}"
    fn fmt(&self, fmt: &str) -> String;
}

impl DateTimeExt for chrono::DateTime<chrono::Local> {
    /// %Y-%m-%d %H:%M:%S%.3f
    /// "{year}-{month}-{day} {hour}:{minute}:{second}.{milisecond}"
    fn fmt(&self, fmt: &str) -> String {
        self.format(fmt).to_string()
    }
}

/// %Y-%m-%d %H:%M:%S%.3f
/// "{year}-{month}-{day} {hour}:{minute}:{second}.{milisecond}"
pub fn fmt_now(fmt: &str) -> String {
    chrono::Local::now().fmt(fmt)
}

/// 休眠毫秒数
pub fn sleep_rand(min: u64, max: u64) {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    let datetime = rng.gen_range(min..max);
    std::thread::sleep(std::time::Duration::from_millis(datetime));
}

/// 获得现在的时候戳
pub fn get_time() -> (u128, u64) {
    let time = std::time::SystemTime::now();
    let time = time.duration_since(std::time::UNIX_EPOCH).unwrap_or_default();
    (time.as_millis(), time.as_secs())
}

/// 获得现在的时候戳
/// ("2020-12-17", "2020-12-17 20:11:16")
/// (现在日期, 现在时间)
pub fn get_now_time_string() -> (String, String) {
    use chrono::Timelike;

    let date = chrono::Local::now().naive_local();

    let year = date.year();
    let month = date.month() as u64;
    let day = date.day() as u64;
    let h = date.hour() as u64;
    let m = date.minute() as u64;
    let s = date.second() as u64;

    let month = get_zoer_val(month);
    let day = get_zoer_val(day);
    let h = get_zoer_val(h);
    let m = get_zoer_val(m);
    let s = get_zoer_val(s);

    let val1 = format!("{}-{}-{}", &year, &month, &day);
    let val2 = format!("{} {}:{}:{}", &val1, &h, &m, &s);
    (val1, val2)
}

#[test]
fn test_get_now_time_string() {
    println!("test_get_now_time_string: {:?}", get_now_time_string());
}

pub fn get_zoer_val(v: u64) -> String {
    let v_str = v.to_string();
    if v_str.len() == 1 {
        "0".to_string() + v_str.as_ref()
    } else {
        v_str
    }
}

/// 获得当前月份 -> ("2020-12-01", "2020-12-17") (月初, 现在日期)
pub fn this_month() -> (String, String) {
    let date = chrono::Local::now().naive_local();
    let year = date.year() as u64;
    let month = date.month() as u64;
    let day = date.day() as u64;
    let begin = format!("{}-{}-01", year, get_zoer_val(month));
    let end = format!("{}-{}-{}", year, get_zoer_val(month), get_zoer_val(day));
    (begin, end)
}

#[test]
pub fn test_this_month() {
    println!("test_this_month {:?}", this_month());
}

/// 获得当前月份: 2020-11
pub fn this_month2() -> String {
    let date = chrono::Local::now().naive_local();
    // let date = Utc::now();
    let year = date.year();
    let month = date.month();
    let begin = format!("{}-{}", year, get_zoer_val(month as u64));
    begin
}

/// 获得上个月份: 2020-10
pub fn last_month2() -> String {
    let date = chrono::Local::now().naive_local();
    // let date = Utc::now();
    let mut date = date.date();
    let mut month = date.month();
    month -= 1;
    if month == 0 {
        month = 12;
        date = date.with_year(date.year() - 1).unwrap_or(date);
    }
    let year = date.year();
    let begin = format!("{}-{}", year, get_zoer_val(month as u64));
    begin
}

#[test]
fn test_last_month2() {
    let mounth = last_month2();
    println!("test_this_month: {:?}", mounth);
}

/// 获得上个月的日期范围
/// return (2010-10-01, 2020-10-31)
pub fn last_month() -> (String, String) {
    month_range("-", 1)
}

#[test]
fn test_last_month() {
    let mounth = last_month();
    println!("mounth: {:?}", mounth);
}

/// 获得上个月的日期范围
/// return (2010-10-01, 2020-10-31)
pub fn month_range(separate: &str, mouth_num: u32) -> (String, String) {
    let (mut begin, mut end, mut date) = month_range2(separate, None);
    for _ in 1..mouth_num {
        let r = month_range2(separate, Some(date));
        begin = r.0;
        end = r.1;
        date = r.2;
    }
    (begin, end)
}
#[test]
pub fn test_month_range() {
    println!("month_range {:?}", month_range("-", 1));
}

fn month_range2(separate: &str, input_month: Option<chrono::NaiveDate>) -> (String, String, chrono::NaiveDate) {
    let mut date = match input_month {
        Some(v) => v,
        None => chrono::Local::today().naive_local(),
    };
    let mut year = date.year();
    let mut month = date.month();
    let begin = {
        if month - 1 == 0 {
            month = 12;
            year -= 1;
        } else {
            month -= 1;
        }
        date.with_day(1).map(|v| date = v);
        date.with_month(month).map(|v| date = v);
        date.with_year(year).map(|v| date = v);
        format!("{}{}{}{}01", year, separate, get_zoer_val(month as u64), separate)
    };

    let end = {
        loop {
            match date.with_day(date.day() + 1) {
                None => break,
                Some(v) => {
                    date = v;
                }
            }
        }
        let day_end = date.day();
        format!("{}{}{}{}{}", year, separate, get_zoer_val(month as u64), separate, get_zoer_val(day_end as u64))
    };

    (begin, end, date)
}

/*#[test]
fn test_last_month1() {
    let mounth = last_month1(4);
    println!("test_last_month1: {:?}", mounth);

    let month = if 9 == 1 {
        let (_, d) = last_month1(1);
        String::sub_string(d, 0, 7)
    } else {
        let (_, d) = last_month1(4);
        String::sub_string(d, 0, 7)
    };

    println!("test_last_month month: {:?}", month);
}*/

/// ("-", 3) -> [("2020-06-01", "2020-06-30"), ("2020-07-01", "2020-07-31"), ("2020-08-01", "2020-08-31")]
pub fn month_vec(separate: &str, mouth_num: u32) -> Vec<(String, String)> {
    let mut arr = vec![];
    for n in (1..=mouth_num).rev() {
        let item = month_range(separate, n);
        arr.push(item);
    }
    arr
}
