use alloc::{boxed::Box, string::String};

use rdif_input::{InputError as RdifInputError, Interface};

use crate::{AbsInfo, Event, EventType, InputDevice, InputDeviceId, InputError, InputResult};

pub struct RdifInputDevice {
    name: String,
    device: Box<dyn Interface>,
}

impl RdifInputDevice {
    pub fn new(device: Box<dyn Interface>) -> Self {
        let name = device.name().into();
        Self { name, device }
    }

    pub fn from_interface(device: impl Interface + 'static) -> Self {
        Self::new(Box::new(device))
    }
}

impl InputDevice for RdifInputDevice {
    fn name(&self) -> &str {
        &self.name
    }

    fn device_id(&self) -> InputDeviceId {
        self.device.device_id().into()
    }

    fn physical_location(&self) -> &str {
        self.device.physical_location()
    }

    fn unique_id(&self) -> &str {
        self.device.unique_id()
    }

    fn get_event_bits(&mut self, ty: EventType, out: &mut [u8]) -> InputResult<bool> {
        self.device
            .get_event_bits(ty.into(), out)
            .map_err(map_input_error)
    }

    fn read_event(&mut self) -> InputResult<Event> {
        self.device
            .read_event()
            .map(Into::into)
            .map_err(map_input_error)
    }

    fn get_prop_bits(&mut self, out: &mut [u8]) -> InputResult<usize> {
        self.device.get_prop_bits(out).map_err(map_input_error)
    }

    fn get_abs_info(&mut self, axis: u8) -> InputResult<AbsInfo> {
        self.device
            .get_abs_info(axis)
            .map(Into::into)
            .map_err(map_input_error)
    }
}

impl From<rdif_input::InputDeviceId> for InputDeviceId {
    fn from(value: rdif_input::InputDeviceId) -> Self {
        Self {
            bus_type: value.bus_type,
            vendor: value.vendor,
            product: value.product,
            version: value.version,
        }
    }
}

impl From<EventType> for rdif_input::EventType {
    fn from(value: EventType) -> Self {
        match value {
            EventType::Synchronization => Self::Synchronization,
            EventType::Key => Self::Key,
            EventType::Relative => Self::Relative,
            EventType::Absolute => Self::Absolute,
            EventType::Misc => Self::Misc,
            EventType::Switch => Self::Switch,
            EventType::Led => Self::Led,
            EventType::Sound => Self::Sound,
            EventType::ForceFeedback => Self::ForceFeedback,
        }
    }
}

impl From<rdif_input::InputEvent> for Event {
    fn from(value: rdif_input::InputEvent) -> Self {
        Self {
            event_type: value.event_type,
            code: value.code,
            value: value.value,
        }
    }
}

impl From<rdif_input::AbsInfo> for AbsInfo {
    fn from(value: rdif_input::AbsInfo) -> Self {
        Self {
            min: value.min,
            max: value.max,
            fuzz: value.fuzz,
            flat: value.flat,
            res: value.res,
        }
    }
}

fn map_input_error(error: RdifInputError) -> InputError {
    match error {
        RdifInputError::NotSupported => InputError::Unsupported,
        RdifInputError::Again => InputError::Again,
        RdifInputError::NotAvailable => InputError::ResourceBusy,
        RdifInputError::InvalidEvent => InputError::InvalidInput,
        RdifInputError::Other(_) => InputError::Io,
    }
}
