#[cfg(target_os = "linux")]
use std::{os::unix::ffi::OsStrExt, path::PathBuf};

use super::*;
use nusb::{Device, Interface, MaybeFuture};

#[derive(Clone, Default, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Version {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
}

/// bcdDevice
impl From<u16> for Version {
    fn from(value: u16) -> Self {
        Self {
            major: (value >> 8) as u8,
            minor: ((value >> 4) & 0xF) as u8,
            patch: (value & 0xF) as u8,
        }
    }
}

impl Version {
    fn bcd_bytes(&self) -> (u8, u8) {
        ((self.minor << 4) | self.patch, self.major)
    }
}

/// Represent a USB device
#[derive(Clone, Default, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct UsbDevice {
    #[cfg(target_os = "linux")]
    pub path: PathBuf,
    #[cfg(not(target_os = "linux"))]
    pub path: String,
    pub bus_id: String,
    pub bus_num: u32,
    pub dev_num: u32,
    pub speed: u32,
    pub vendor_id: u16,
    pub product_id: u16,
    pub device_bcd: Version,
    pub device_class: u8,
    pub device_subclass: u8,
    pub device_protocol: u8,
    pub configuration_value: u8,
    pub num_configurations: u8,
    pub interfaces: Vec<UsbInterface>,

    #[cfg_attr(feature = "serde", serde(skip))]
    pub device_handler: Option<Device>,

    pub usb_version: Version,
    pub attributes: u8,
    pub max_power: u8,

    pub(crate) ep0_in: UsbEndpoint,
    pub(crate) ep0_out: UsbEndpoint,
    // strings
    pub(crate) string_pool: HashMap<u8, String>,
    pub(crate) string_configuration: u8,
    pub(crate) string_manufacturer: u8,
    pub(crate) string_product: u8,
    pub(crate) string_serial: u8,
}

impl UsbDevice {
    pub fn new(index: u32) -> Self {
        let mut res = Self {
            #[cfg(target_os = "linux")]
            path: PathBuf::from(String::from("/sys/bus/0/0/0")),
            #[cfg(not(target_os = "linux"))]
            path: String::from("/sys/bus/0/0/0"),
            bus_id: "0-0-0".to_string(),
            dev_num: index,
            speed: UsbSpeed::High as u32,
            ep0_in: UsbEndpoint {
                address: 0x80,
                attributes: EndpointAttributes::Control as u8,
                max_packet_size: EP0_MAX_PACKET_SIZE,
                interval: 0,
            },
            ep0_out: UsbEndpoint {
                address: 0x00,
                attributes: EndpointAttributes::Control as u8,
                max_packet_size: EP0_MAX_PACKET_SIZE,
                interval: 0,
            },
            // configured by default
            configuration_value: 1,
            num_configurations: 1,
            ..Self::default()
        };
        res.string_configuration = res.new_string("Default Configuration");
        res.string_manufacturer = res.new_string("Manufacturer");
        res.string_product = res.new_string("Product");
        res.string_serial = res.new_string("Serial");
        res
    }

    /// Returns the old value, if present.
    pub fn set_configuration_name(&mut self, name: &str) -> Option<String> {
        let old = (self.string_configuration != 0)
            .then(|| self.string_pool.remove(&self.string_configuration))
            .flatten();
        self.string_configuration = self.new_string(name);
        old
    }

    /// Unset configuration name and returns the old value, if present.
    pub fn unset_configuration_name(&mut self) -> Option<String> {
        let old = (self.string_configuration != 0)
            .then(|| self.string_pool.remove(&self.string_configuration))
            .flatten();
        self.string_configuration = 0;
        old
    }

    fn is_superspeed(&self) -> bool {
        self.speed >= UsbSpeed::Super as u32
    }

    fn ep0_descriptor_size(&self) -> u8 {
        if self.is_superspeed() {
            9
        } else {
            self.ep0_in.max_packet_size as u8
        }
    }

    fn bos_descriptor(&self) -> Vec<u8> {
        if !self.is_superspeed() {
            return vec![0x05, DescriptorType::BOS as u8, 0x05, 0x00, 0x00];
        }

        let mut desc = vec![
            0x05,
            DescriptorType::BOS as u8,
            0x16,
            0x00,
            0x02,
            0x07,
            DescriptorType::DeviceCapability as u8,
            0x02,
            0x02,
            0x00,
            0x00,
            0x00,
            0x0A,
            DescriptorType::DeviceCapability as u8,
            0x03,
            0x00,
            0x0E,
            0x00,
            0x01,
            0x0A,
            0xFF,
            0x07,
        ];
        let len = desc.len() as u16;
        desc[2] = len as u8;
        desc[3] = (len >> 8) as u8;
        desc
    }

    fn should_forward_set_configuration(&self, requested_configuration: u8) -> bool {
        requested_configuration != self.configuration_value
    }

    fn handles_mass_storage_get_max_lun(&self, setup_packet: SetupPacket) -> bool {
        setup_packet.request_type == 0xA1
            && setup_packet.request == 0xFE
            && setup_packet.value == 0
            && setup_packet.length == 1
            && self
                .interfaces
                .get((setup_packet.index & 0xFF) as usize)
                .is_some_and(|intf| {
                    is_mass_storage_bulk_only_interface(
                        intf.interface_class,
                        intf.interface_subclass,
                        intf.interface_protocol,
                    )
                })
    }

    fn handles_superspeed_virtual_request(&self, setup_packet: SetupPacket) -> bool {
        self.is_superspeed()
            && setup_packet.request_type == 0x00
            && (setup_packet.request == 0x30 || setup_packet.request == 0x31)
    }

    /// Returns the old value, if present.
    pub fn set_serial_number(&mut self, name: &str) -> Option<String> {
        let old = (self.string_serial != 0)
            .then(|| self.string_pool.remove(&self.string_serial))
            .flatten();
        self.string_serial = self.new_string(name);
        old
    }

    /// Unset serial number and returns the old value, if present.
    pub fn unset_serial_number(&mut self) -> Option<String> {
        let old = (self.string_serial != 0)
            .then(|| self.string_pool.remove(&self.string_serial))
            .flatten();
        self.string_serial = 0;
        old
    }

    /// Returns the old value, if present.
    pub fn set_product_name(&mut self, name: &str) -> Option<String> {
        let old = (self.string_product != 0)
            .then(|| self.string_pool.remove(&self.string_product))
            .flatten();
        self.string_product = self.new_string(name);
        old
    }

    /// Unset product name and returns the old value, if present.
    pub fn unset_product_name(&mut self) -> Option<String> {
        let old = (self.string_product != 0)
            .then(|| self.string_pool.remove(&self.string_product))
            .flatten();
        self.string_product = 0;
        old
    }

    /// Returns the old value, if present.
    pub fn set_manufacturer_name(&mut self, name: &str) -> Option<String> {
        let old = (self.string_manufacturer != 0)
            .then(|| self.string_pool.remove(&self.string_manufacturer))
            .flatten();
        self.string_manufacturer = self.new_string(name);
        old
    }

    /// Unset manufacturer name and returns the old value, if present.
    pub fn unset_manufacturer_name(&mut self) -> Option<String> {
        let old = (self.string_manufacturer != 0)
            .then(|| self.string_pool.remove(&self.string_manufacturer))
            .flatten();
        self.string_manufacturer = 0;
        old
    }

    pub fn with_interface(
        mut self,
        interface_class: u8,
        interface_subclass: u8,
        interface_protocol: u8,
        name: Option<&str>,
        endpoints: Vec<UsbEndpoint>,
        handler: Interface,
    ) -> Self {
        let string_interface = name.map(|name| self.new_string(name)).unwrap_or(0);
        let class_specific_descriptor = Vec::new();
        self.interfaces.push(UsbInterface {
            interface_class,
            interface_subclass,
            interface_protocol,
            endpoints,
            string_interface,
            class_specific_descriptor,
            handler,
        });
        self
    }

    pub fn with_device_handler(mut self, handler: Device) -> Self {
        self.device_handler = Some(handler);
        self
    }

    pub(crate) fn new_string(&mut self, s: &str) -> u8 {
        for i in 1.. {
            if let std::collections::hash_map::Entry::Vacant(e) = self.string_pool.entry(i) {
                e.insert(s.to_string());
                return i;
            }
        }
        panic!("string poll exhausted")
    }

    pub(crate) fn find_ep(&self, ep: u8) -> Option<(UsbEndpoint, Option<&UsbInterface>)> {
        if ep == self.ep0_in.address {
            Some((self.ep0_in, None))
        } else if ep == self.ep0_out.address {
            Some((self.ep0_out, None))
        } else {
            for intf in &self.interfaces {
                for endpoint in &intf.endpoints {
                    if endpoint.address == ep {
                        return Some((*endpoint, Some(intf)));
                    }
                }
            }
            None
        }
    }

    pub(crate) fn to_bytes(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(312);
        #[cfg(target_os = "linux")]
        let mut path = self.path.clone().as_os_str().as_bytes().to_vec();
        #[cfg(not(target_os = "linux"))]
        let mut path = self.path.clone().as_bytes().to_vec();
        debug_assert!(path.len() <= 256);
        path.resize(256, 0);
        result.extend_from_slice(path.as_slice());

        let mut bus_id = self.bus_id.as_bytes().to_vec();
        debug_assert!(bus_id.len() <= 32);
        bus_id.resize(32, 0);
        result.extend_from_slice(bus_id.as_slice());

        result.extend_from_slice(&self.bus_num.to_be_bytes());
        result.extend_from_slice(&self.dev_num.to_be_bytes());
        result.extend_from_slice(&self.speed.to_be_bytes());
        result.extend_from_slice(&self.vendor_id.to_be_bytes());
        result.extend_from_slice(&self.product_id.to_be_bytes());
        result.push(self.device_bcd.major);
        result.push(self.device_bcd.minor);
        result.push(self.device_class);
        result.push(self.device_subclass);
        result.push(self.device_protocol);
        result.push(self.configuration_value);
        result.push(self.num_configurations);
        result.push(self.interfaces.len() as u8);

        result
    }

    pub(crate) fn to_bytes_with_interfaces(&self) -> Vec<u8> {
        let mut result = self.to_bytes();
        result.reserve(4 * self.interfaces.len());

        for intf in &self.interfaces {
            result.push(intf.interface_class);
            result.push(intf.interface_subclass);
            result.push(intf.interface_protocol);
            result.push(0); // padding
        }

        result
    }

    pub(crate) fn handle_urb(
        &self,
        ep: UsbEndpoint,
        intf: Option<&UsbInterface>,
        transfer_buffer_length: u32,
        setup_packet: SetupPacket,
        out_data: &[u8],
    ) -> Result<Vec<u8>> {
        use DescriptorType::*;
        use Direction::*;
        use EndpointAttributes::*;
        use StandardRequest::*;

        // let intf_num = match intf {
        //     Some(i) => i.handler.interface_number(),
        //     None => 0,
        // };
        // let device = match self.device_handler.clone() {
        //     Some(dev) => {
        //         #[cfg(target_os = "linux")]
        //         if let Err(e) = dev.detach_kernel_driver(intf_num) {
        //             error!("Failed to detach kernel driver: {e:?}");
        //         }
        //         dev.claim_interface(intf_num).wait()?;
        //         dev
        //     }
        //     None => return Err(std::io::Error::new(ErrorKind::NotFound, "No device found")),
        // };

        match (FromPrimitive::from_u8(ep.attributes), ep.direction()) {
            (Some(Control), In) => {
                // control in
                debug!("Control IN setup={setup_packet:x?}");
                match (
                    setup_packet.request_type,
                    FromPrimitive::from_u8(setup_packet.request),
                ) {
                    (0b10000000, Some(GetDescriptor)) => {
                        // high byte: type
                        match FromPrimitive::from_u16(setup_packet.value >> 8) {
                            Some(Device) => {
                                debug!("Get device descriptor");
                                let (usb_lo, usb_hi) = self.usb_version.bcd_bytes();
                                let (device_lo, device_hi) = self.device_bcd.bcd_bytes();
                                // Standard Device Descriptor
                                let mut desc = vec![
                                    0x12,         // bLength
                                    Device as u8, // bDescriptorType: Device
                                    usb_lo,
                                    usb_hi,                     // bcdUSB
                                    self.device_class,          // bDeviceClass
                                    self.device_subclass,       // bDeviceSubClass
                                    self.device_protocol,       // bDeviceProtocol
                                    self.ep0_descriptor_size(), // bMaxPacketSize0
                                    self.vendor_id as u8,       // idVendor
                                    (self.vendor_id >> 8) as u8,
                                    self.product_id as u8, // idProduct
                                    (self.product_id >> 8) as u8,
                                    device_lo, // bcdDevice
                                    device_hi,
                                    self.string_manufacturer, // iManufacturer
                                    self.string_product,      // iProduct
                                    self.string_serial,       // iSerial
                                    self.num_configurations,  // bNumConfigurations
                                ];

                                // requested len too short: wLength < real length
                                if setup_packet.length < desc.len() as u16 {
                                    desc.resize(setup_packet.length as usize, 0);
                                }
                                Ok(desc)
                            }
                            Some(BOS) => {
                                debug!("Get BOS descriptor");
                                let mut desc = self.bos_descriptor();

                                // requested len too short: wLength < real length
                                if setup_packet.length < desc.len() as u16 {
                                    desc.resize(setup_packet.length as usize, 0);
                                }
                                Ok(desc)
                            }
                            Some(Configuration) => {
                                debug!("Get configuration descriptor");
                                // Standard Configuration Descriptor
                                let mut desc = vec![
                                    0x09,                // bLength
                                    Configuration as u8, // bDescriptorType: Configuration
                                    0x00,
                                    0x00, // wTotalLength: to be filled below
                                    self.interfaces.len() as u8, // bNumInterfaces
                                    self.configuration_value, // bConfigurationValue
                                    self.string_configuration, // iConfiguration
                                    self.attributes, // bmAttributes: Bus Powered
                                    self.max_power, // bMaxPower: 100mA
                                ];
                                for (i, intf) in self.interfaces.iter().enumerate() {
                                    let mut intf_desc = vec![
                                        0x09,                       // bLength
                                        Interface as u8,            // bDescriptorType: Interface
                                        i as u8,                    // bInterfaceNum
                                        0x00,                       // bAlternateSettings
                                        intf.endpoints.len() as u8, // bNumEndpoints
                                        intf.interface_class,       // bInterfaceClass
                                        intf.interface_subclass,    // bInterfaceSubClass
                                        intf.interface_protocol,    // bInterfaceProtocol
                                        intf.string_interface,      //iInterface
                                    ];
                                    // class specific endpoint
                                    let mut specific = intf.class_specific_descriptor.clone();
                                    intf_desc.append(&mut specific);
                                    // endpoint descriptors
                                    for endpoint in &intf.endpoints {
                                        let mut ep_desc = vec![
                                            0x07,                // bLength
                                            Endpoint as u8,      // bDescriptorType: Endpoint
                                            endpoint.address,    // bEndpointAddress
                                            endpoint.attributes, // bmAttributes
                                            endpoint.max_packet_size as u8,
                                            (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize
                                            endpoint.interval,                     // bInterval
                                        ];
                                        intf_desc.append(&mut ep_desc);
                                        if self.is_superspeed() {
                                            let mut ss_companion =
                                                superspeed_endpoint_companion_descriptor(endpoint);
                                            intf_desc.append(&mut ss_companion);
                                        }
                                    }
                                    desc.append(&mut intf_desc);
                                }
                                // length
                                let len = desc.len() as u16;
                                desc[2] = len as u8;
                                desc[3] = (len >> 8) as u8;

                                // requested len too short: wLength < real length
                                if setup_packet.length < desc.len() as u16 {
                                    desc.resize(setup_packet.length as usize, 0);
                                }
                                Ok(desc)
                            }
                            Some(String) => {
                                debug!("Get string descriptor");
                                let index = setup_packet.value as u8;
                                if index == 0 {
                                    // String Descriptor Zero, Specifying Languages Supported by the Device
                                    // language ids
                                    let mut desc = vec![
                                        4,                            // bLength
                                        DescriptorType::String as u8, // bDescriptorType
                                        0x09,
                                        0x04, // wLANGID[0], en-US
                                    ];
                                    // requested len too short: wLength < real length
                                    if setup_packet.length < desc.len() as u16 {
                                        desc.resize(setup_packet.length as usize, 0);
                                    }
                                    Ok(desc)
                                } else if let Some(s) = &self.string_pool.get(&index) {
                                    // UNICODE String Descriptor
                                    let bytes: Vec<u16> = s.encode_utf16().collect();
                                    let mut desc = vec![
                                        2 + bytes.len() as u8 * 2,    // bLength
                                        DescriptorType::String as u8, // bDescriptorType
                                    ];
                                    for byte in bytes {
                                        desc.push(byte as u8);
                                        desc.push((byte >> 8) as u8);
                                    }

                                    // requested len too short: wLength < real length
                                    if setup_packet.length < desc.len() as u16 {
                                        desc.resize(setup_packet.length as usize, 0);
                                    }
                                    Ok(desc)
                                } else {
                                    Err(std::io::Error::new(
                                        std::io::ErrorKind::InvalidInput,
                                        format!("Invalid string index: {index}"),
                                    ))
                                }
                            }
                            Some(DeviceQualifier) => {
                                debug!("Get device qualifier descriptor");
                                let (usb_lo, usb_hi) = self.usb_version.bcd_bytes();
                                // Device_Qualifier Descriptor
                                let mut desc = vec![
                                    0x0A,                  // bLength
                                    DeviceQualifier as u8, // bDescriptorType: Device Qualifier
                                    usb_lo,
                                    usb_hi,                     // bcdUSB
                                    self.device_class,          // bDeviceClass
                                    self.device_subclass,       // bDeviceSUbClass
                                    self.device_protocol,       // bDeviceProtocol
                                    self.ep0_descriptor_size(), // bMaxPacketSize0
                                    self.num_configurations,    // bNumConfigurations
                                    0x00,                       // bReserved
                                ];

                                // requested len too short: wLength < real length
                                if setup_packet.length < desc.len() as u16 {
                                    desc.resize(setup_packet.length as usize, 0);
                                }
                                Ok(desc)
                            }
                            _ => {
                                warn!("unknown desc type: {setup_packet:x?}");
                                Ok(vec![])
                            }
                        }
                    }
                    _ if self.handles_mass_storage_get_max_lun(setup_packet) => {
                        debug!("Get max LUN");
                        Ok(vec![0])
                    }
                    _ if setup_packet.request_type & 0xF == 1 => {
                        // to interface
                        // see https://www.beyondlogic.org/usbnutshell/usb6.shtml
                        // only low 8 bits are valid
                        // let device = match self.device_handler.clone() {
                        //     Some(dev) => dev,
                        //     None => {
                        //         return Ok(Vec::new());
                        //     }
                        // };
                        let intf = &self.interfaces[setup_packet.index as usize & 0xFF];
                        let handler = intf.handler.clone();
                        handle_urb_for_interface(
                            handler,
                            // device,
                            ep,
                            transfer_buffer_length,
                            setup_packet,
                            out_data,
                        )
                    }
                    _ if setup_packet.request_type & 0xF == 0 && self.device_handler.is_some() => {
                        // to device
                        // see https://www.beyondlogic.org/usbnutshell/usb6.shtml
                        let handler = self.device_handler.clone().unwrap();
                        handle_urb_for_device(
                            handler,
                            transfer_buffer_length,
                            setup_packet,
                            out_data,
                        )
                    }
                    _ => unimplemented!("control in"),
                }
            }
            (Some(Control), Out) => {
                // control out
                debug!("Control OUT setup={setup_packet:x?}");
                match (
                    setup_packet.request_type,
                    FromPrimitive::from_u8(setup_packet.request),
                ) {
                    (0b00000000, Some(SetConfiguration)) => {
                        let mut desc = vec![
                            self.configuration_value, // bConfigurationValue
                        ];
                        if let Some(device) = self.device_handler.clone() {
                            #[cfg(target_os = "linux")]
                            match intf {
                                Some(i) => {
                                    if let Err(e) =
                                        device.detach_kernel_driver(i.handler.interface_number())
                                    {
                                        error!("Failed to detach kernel driver: {e:?}");
                                    }
                                }
                                None => {
                                    if let Err(e) = device.detach_kernel_driver(0) {
                                        error!("Failed to detach kernel driver: {e:?}");
                                    }
                                }
                            }
                            if self.should_forward_set_configuration(setup_packet.value as u8) {
                                if let Err(e) =
                                    device.set_configuration(setup_packet.value as u8).wait()
                                {
                                    error!("Error setting config: {e:?}");
                                };
                            }
                        }
                        // requested len too short: wLength < real length
                        if setup_packet.length < desc.len() as u16 {
                            desc.resize(setup_packet.length as usize, 0);
                        }
                        Ok(desc)
                    }
                    _ if self.handles_superspeed_virtual_request(setup_packet) => {
                        debug!("Ack SuperSpeed virtual request");
                        Ok(Vec::new())
                    }
                    _ if setup_packet.request_type & 0xF == 1 => {
                        // to interface
                        // see https://www.beyondlogic.org/usbnutshell/usb6.shtml
                        // only low 8 bits are valid

                        let intf = &self.interfaces[setup_packet.index as usize & 0xFF];
                        let interface = intf.handler.clone();
                        // let device = match self.device_handler.clone() {
                        //     Some(dev) => dev,
                        //     None => {
                        //         return Ok(Vec::new());
                        //     }
                        // };
                        handle_urb_for_interface(
                            interface,
                            // device,
                            ep,
                            transfer_buffer_length,
                            setup_packet,
                            out_data,
                        )
                    }
                    _ if setup_packet.request_type & 0xF == 0 => {
                        // to device
                        // see https://www.beyondlogic.org/usbnutshell/usb6.shtml
                        match self.device_handler.clone() {
                            Some(dh) => handle_urb_for_device(
                                dh,
                                transfer_buffer_length,
                                setup_packet,
                                out_data,
                            ),
                            None => Ok(Vec::new()),
                        }
                    }
                    _ => unimplemented!("control out"),
                }
            }
            _ => {
                // others
                // if setup_packet.request_type & 0xf == 1 {
                //     let intf = &self.interfaces[setup_packet.index as usize & 0xFF];
                //     let mut handler = intf.handler.lock().unwrap();
                //     handler.handle_urb(intf, ep, transfer_buffer_length, setup_packet, out_data)
                // } else if setup_packet.request_type & 0xf == 0 {
                //     match self.device_handler.clone() {
                //         Some(dh) => {
                //             let mut handler = dh.lock().unwrap();
                //             handler.handle_urb(transfer_buffer_length, setup_packet, out_data)
                //         }
                //         None => Ok(Vec::new()),
                //     }
                // } else {
                //     Ok(Vec::new())
                // }
                // info!("ep: {ep:?}. interface: {intf:?}");
                let intf = intf.unwrap();
                let interface = intf.handler.clone();
                // let device = match self.device_handler.clone() {
                //     Some(dev) => dev,
                //     None => {
                //         return Ok(Vec::new());
                //     }
                // };
                handle_urb_for_interface(
                    interface,
                    // device,
                    ep,
                    transfer_buffer_length,
                    setup_packet,
                    out_data,
                )
            } // _ => unimplemented!("transfer to {:?}", ep),
        }
    }
}

fn is_mass_storage_bulk_only_interface(class: u8, subclass: u8, protocol: u8) -> bool {
    class == 0x08 && subclass == 0x06 && protocol == 0x50
}

fn superspeed_endpoint_companion_descriptor(endpoint: &UsbEndpoint) -> Vec<u8> {
    let bytes_per_interval = if endpoint.attributes == EndpointAttributes::Interrupt as u8 {
        endpoint.max_packet_size
    } else {
        0
    };
    vec![
        0x06,
        DescriptorType::SuperspeedUsbEndpointCompanion as u8,
        0x00,
        0x00,
        bytes_per_interval as u8,
        (bytes_per_interval >> 8) as u8,
    ]
}

/// A handler for URB targeting the device
pub trait UsbDeviceHandler: std::fmt::Debug {
    /// Handle a URB(USB Request Block) targeting at this device
    ///
    /// When the lower 4 bits of `bmRequestType` is zero and the URB is not handled by the library, this function is called.
    /// The resulting data should not exceed `transfer_buffer_length`
    fn handle_urb(
        &mut self,
        transfer_buffer_length: u32,
        setup: SetupPacket,
        req: &[u8],
    ) -> Result<Vec<u8>>;

    /// Reattach the kernel driver
    #[cfg(target_os = "linux")]
    fn release_claim(&mut self);

    /// Reset the device, forcing it to re-enumerate.
    /// This Device will no longer be usable, and you should drop it and call list_devices to find and re-open it again.
    #[cfg(not(target_os = "windows"))]
    fn reset(&mut self) -> Result<()>;

    /// Set the device configuration.
    /// The argument is the desired configuration’s `bConfigurationValue` descriptor field from `ConfigurationDescriptor::configuration_value` or `0` to unconfigure the device.
    #[cfg(not(target_os = "windows"))]
    fn set_configuration(&self, setup: &[u8; 8]) -> Result<()>;

    /// Helper to downcast to actual struct
    ///
    /// Please implement it as:
    /// ```ignore
    /// fn as_any(&mut self) -> &mut dyn Any {
    ///     self
    /// }
    /// ```
    fn as_any(&mut self) -> &mut dyn Any;
}

#[cfg(target_os = "linux")]
pub fn release_claim(device: Device) {
    let cfg = match device.active_configuration() {
        Ok(cfg) => cfg,
        Err(err) => {
            warn!("Impossible to get active configuration: {err}, ignoring device",);
            return;
        }
    };
    for intf in cfg.interfaces() {
        // ignore alternate settings
        let intf_num = intf.interface_number();
        let _ = device.attach_kernel_driver(intf_num);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn set_configuration_is_not_forwarded_when_already_active() {
        let mut device = UsbDevice::new(1);
        device.configuration_value = 1;

        assert!(!device.should_forward_set_configuration(1));
        assert!(device.should_forward_set_configuration(0));
        assert!(device.should_forward_set_configuration(2));
    }

    #[test]
    fn identifies_mass_storage_bulk_only_interface() {
        assert!(is_mass_storage_bulk_only_interface(0x08, 0x06, 0x50));
        assert!(!is_mass_storage_bulk_only_interface(0x08, 0x06, 0x62));
        assert!(!is_mass_storage_bulk_only_interface(0xFF, 0x00, 0x00));
    }

    #[test]
    fn superspeed_virtual_requests_are_handled_locally() {
        let mut device = UsbDevice::new(1);
        device.speed = UsbSpeed::Super as u32;

        assert!(device.handles_superspeed_virtual_request(SetupPacket {
            request_type: 0x00,
            request: 0x30,
            value: 0,
            index: 0,
            length: 6,
        }));
        assert!(device.handles_superspeed_virtual_request(SetupPacket {
            request_type: 0x00,
            request: 0x31,
            value: 0x28,
            index: 0,
            length: 0,
        }));
    }
}
