use std::ffi::CString;

use serde::{Deserialize, Serialize};
use sysinfo::Disks;
use windows::{
	core::PCSTR,
	Win32::Storage::FileSystem::{
		GetDiskFreeSpaceExA, GetLogicalDriveStringsW, GetVolumeInformationA,
	},
};

use crate::dtos::storage::DiskInfo;

pub fn get_storage_info() -> Vec<DiskInfo> {
	// Initialize a buffer to hold the drive strings.
	let mut buffer: [u16; 256] = [0; 256];

	// Get the list of logical drives using the Windows API function GetLogicalDriveStringsW.
	let _ = unsafe {
		GetLogicalDriveStringsW(Some(&mut buffer)) as usize
	};

	// Split the buffer into individual drive strings.
	let mut disk_info_list = vec![];

	// Initialize an empty vector to store the disk information.
	let drives: Vec<&[u16]> = buffer.split(|&c| c == 0).collect();

	// Iterate over each drive string.
	for drive in drives {
		// Skip empty drive strings.
		if drive.is_empty() {
			continue;
		}

		// Convert the drive string to a Rust string.
		let drive_str = String::from_utf16_lossy(drive);

		// Convert the drive string to a C string.
		let drive_cstr = CString::new(drive_str.clone()).unwrap();

		// Initialize buffers to hold volume information.
		let mut volume_name = [0u8; 128];
		let mut serial_number: u32 = 0;
		let mut lp_maximum_component_length: u32 = 0;
		let mut file_system_name = [0u8; 128];
		let mut lp_total_number_of_bytes: u64 = 0;

		// Retrieve volume information using the Windows API function GetVolumeInformationA.
		unsafe {
			let _ = GetVolumeInformationA(
				PCSTR(drive_cstr.as_ptr() as *const u8),
				Some(&mut volume_name),
				Some(&mut serial_number),
				Some(&mut lp_maximum_component_length),
				None,
				Some(&mut file_system_name),
			);

			// Retrieve disk free space using the Windows API function GetDiskFreeSpaceExA.
			let _ = GetDiskFreeSpaceExA(None, None, Some(&mut lp_total_number_of_bytes), None);
		}

		// Create a DiskInfo struct and push it to the disk_info_list vector.
		disk_info_list.push(DiskInfo {
			name: String::from_utf8_lossy(&volume_name)
				.trim_matches('\0')
				.to_string(),
			model: String::from_utf8_lossy(&file_system_name)
				.trim_matches('\0')
				.to_string(),
			serial_number: format!("{}", serial_number),
			size: lp_total_number_of_bytes,
		})
	}

	// Return the vector of disk information.
	disk_info_list
}
