use anyhow::{bail, format_err, Error};
use std::io::Read;
use endian_trait::Endian;
use std::os::unix::io::AsRawFd;

use proxmox::tools::io::ReadExt;

use crate::sgutils2::SgRaw;

#[repr(C, packed)]
#[derive(Endian)]
struct DesnityDescriptorBlock {
    primary_density_code: u8,
    secondary_density_code: u8,
    flags2: u8,
    reserved: [u8; 2],
    bits_per_mm: [u8; 3],
    media_width: u16,
    tracks: u16,
    capacity: u32,
    organizazion: [u8; 8],
    density_name: [u8; 8],
    description: [u8; 20],
}

// Returns the maximum supported drive density code
pub fn report_density<F: AsRawFd>(file: &mut F) -> Result<u8, Error> {
    let alloc_len: u16 = 8192;
    let mut sg_raw = SgRaw::new(file,  alloc_len as usize)?;

    let mut cmd = Vec::new();
    cmd.extend(&[0x44, 0, 0, 0, 0, 0, 0]); // REPORT DENSITY SUPPORT (MEDIA=0)
    cmd.extend(&alloc_len.to_be_bytes()); // alloc len
    cmd.push(0u8); // control byte

    let data = sg_raw.do_command(&cmd)
        .map_err(|err| format_err!("report density failed - {}", err))?;

    let mut max_density = 0u8;

    proxmox::try_block!({
        let mut reader = &data[..];

        let page_len: u16 = unsafe { reader.read_be_value()? };
        let page_len = page_len as usize;

        if (page_len + 2) > data.len() {
            bail!("invalid page length {} {}", page_len + 2, data.len());
        } else {
            // Note: Quantum hh7 returns the allocation_length instead of real data_len
            reader = &data[2..page_len+2];
        }
        let mut reserved = [0u8; 2];
        reader.read_exact(&mut reserved)?;

        loop {
            if reader.is_empty() { break; }
            let block: DesnityDescriptorBlock = unsafe { reader.read_be_value()? };
            if block.primary_density_code > max_density {
                max_density = block.primary_density_code;
            }
        }

        Ok(())

    }).map_err(|err| format_err!("decode report density failed - {}", err))?;

    Ok(max_density)
}
