
pub const MAJOR_VERSION: u16 = 0;

pub const MINOR_VERSION: u16 = 18;

pub const BUILD_NUMBER: u16 = 102;

pub fn version() -> String {
    format!("{}.{}.{}", MAJOR_VERSION, MINOR_VERSION, BUILD_NUMBER)
}

#[derive(Debug, Clone, Default)]
pub struct DllVersion {

    pub major: u16,

    pub minor: u16,

    pub patch: u16,

    pub build: u16,

    pub build_date: String,
}

impl std::fmt::Display for DllVersion {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}.{}.{}.{}", self.major, self.minor, self.patch, self.build)
    }
}

pub fn dll_version() -> Option<DllVersion> {
    let ptr = unsafe { crate::utils::ffi::GetDllVersionInfo() };
    if ptr.is_null() {
        return None;
    }

    let info = unsafe { std::ptr::read_unaligned(ptr) };
    let build_date_raw = unsafe { std::ptr::addr_of!(info.build_date).read_unaligned() };
    let null_pos = build_date_raw.iter().position(|&b| b == 0).unwrap_or(build_date_raw.len());
    let build_date = String::from_utf8_lossy(&build_date_raw[..null_pos]).to_string();

    Some(DllVersion {
        major: unsafe { std::ptr::addr_of!(info.major).read_unaligned() },
        minor: unsafe { std::ptr::addr_of!(info.minor).read_unaligned() },
        patch: unsafe { std::ptr::addr_of!(info.patch).read_unaligned() },
        build: unsafe { std::ptr::addr_of!(info.build).read_unaligned() },
        build_date,
    })
}
