use core::{cmp::Ordering, mem::MaybeUninit, ptr::null_mut};

use chrono::Utc;

use crate::headers::{sys_types::time_t, time::tm};

use super::{get_timezone, CDateTime};

#[allow(static_mut_refs)]
#[no_mangle]
unsafe extern "C" fn gmtime(tp: *const time_t) -> *mut tm {
    static mut BUFFER: MaybeUninit<tm> = MaybeUninit::uninit();
    gmtime_r(tp, BUFFER.as_mut_ptr())
}

#[no_mangle]
unsafe extern "C" fn gmtime_r(tp: *const time_t, timep: *mut tm) -> *mut tm {
    let tp = tp.as_ref().unwrap();
    let timep = timep.as_mut().unwrap();

    match tp.to_datetime(Utc) {
        Some(t) => {
            *timep = t.into();
            timep
        }
        None => null_mut(),
    }
}

#[allow(static_mut_refs)]
#[no_mangle]
unsafe extern "C" fn localtime(tp: *const time_t) -> *mut tm {
    static mut BUFFER: MaybeUninit<tm> = MaybeUninit::uninit();
    localtime_r(tp, BUFFER.as_mut_ptr())
}

#[no_mangle]
unsafe extern "C" fn localtime_r(tp: *const time_t, timep: *mut tm) -> *mut tm {
    let tp = tp.as_ref().unwrap();
    let timep = timep.as_mut().unwrap();

    let tz = get_timezone();
    match tp.to_datetime(tz) {
        Some(t) => {
            *timep = t.into();
            timep
        }
        None => null_mut(),
    }
}

#[no_mangle]
unsafe extern "C" fn mktime(timep: *const tm) -> time_t {
    let timep = timep.as_ref().unwrap();
    let _is_dst = match timep.tm_isdst.cmp(&0) {
        Ordering::Less => todo!(),
        Ordering::Equal => false,
        Ordering::Greater => true,
    };

    let tz = get_timezone();
    match timep.to_datetime(tz) {
        Some(t) => time_t(t.timestamp() as _),
        None => time_t::INVALID,
    }
}
