// SPDX-License-Identifier: MPL-2.0

use alloc::{sync::Arc, vec::Vec};
use core::{any::Any, fmt::Debug};

use ostd::{
    Pod,
    sync::{RwLock, WriteIrqDisabled},
};

use crate::{
    event_type_codes::{EventTypes, KeyCode, KeyCodeSet, KeyStatus, RelCode, RelCodeSet, SynEvent},
    input_handler::BoundInputHandler,
    unregister_device,
};

/// Input event.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InputEvent {
    /// Synchronization events (EV_SYN)
    Sync(SynEvent),
    /// Key press/release events (EV_KEY)
    Key(KeyCode, KeyStatus),
    /// Relative movement events (EV_REL)
    Relative(RelCode, i32),
    // TODO: Add EV_ABS, EV_MSC, EV_SW, EV_LED, EV_SND, ... as needed
}

impl InputEvent {
    /// Creates a synchronization event.
    pub fn from_sync_event(sync_type: SynEvent) -> Self {
        Self::Sync(sync_type)
    }

    /// Creates a key event.
    pub fn from_key_and_status(key: KeyCode, status: KeyStatus) -> Self {
        Self::Key(key, status)
    }

    /// Creates a relative movement event.
    pub fn from_relative_move(axis: RelCode, value: i32) -> Self {
        Self::Relative(axis, value)
    }

    /// Converts enum to raw Linux input event triplet (type, code, value).
    pub fn to_raw(&self) -> (u16, u16, i32) {
        match self {
            InputEvent::Sync(sync_type) => (
                EventTypes::SYN.as_index(),
                *sync_type as u16,
                0, // Sync events always have value = 0
            ),
            InputEvent::Key(key, status) => {
                (EventTypes::KEY.as_index(), *key as u16, *status as i32)
            }
            InputEvent::Relative(axis, value) => (EventTypes::REL.as_index(), *axis as u16, *value),
        }
    }

    /// Gets the event type.
    pub fn event_type(&self) -> EventTypes {
        match self {
            InputEvent::Sync(_) => EventTypes::SYN,
            InputEvent::Key(_, _) => EventTypes::KEY,
            InputEvent::Relative(_, _) => EventTypes::REL,
        }
    }
}

/// Input device identifier.
#[repr(C)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct InputId {
    /// Bus type identifier.
    bustype: u16,
    /// Vendor ID of the device manufacturer.
    vendor: u16,
    /// Product ID of the specific device model.
    product: u16,
    /// Version number of the device.
    version: u16,
}

impl InputId {
    /// Creates a new `InputId` with the specified values.
    pub fn new(bustype: u16, vendor: u16, product: u16, version: u16) -> Self {
        Self {
            bustype,
            vendor,
            product,
            version,
        }
    }

    /// Gets the bus type.
    pub fn bustype(&self) -> u16 {
        self.bustype
    }

    /// Gets the vendor ID.
    pub fn vendor(&self) -> u16 {
        self.vendor
    }

    /// Gets the product ID.
    pub fn product(&self) -> u16 {
        self.product
    }

    /// Gets the version number.
    pub fn version(&self) -> u16 {
        self.version
    }

    // Common bus types.
    pub const BUS_PCI: u16 = 0x01;
    pub const BUS_ISAPNP: u16 = 0x02;
    pub const BUS_USB: u16 = 0x03;
    pub const BUS_HIL: u16 = 0x04;
    pub const BUS_BLUETOOTH: u16 = 0x05;
    pub const BUS_VIRTUAL: u16 = 0x06;
    pub const BUS_ISA: u16 = 0x10;
    pub const BUS_I8042: u16 = 0x11;
    pub const BUS_XTKBD: u16 = 0x12;
    pub const BUS_RS232: u16 = 0x13;
    pub const BUS_GAMEPORT: u16 = 0x14;
    pub const BUS_PARPORT: u16 = 0x15;
    pub const BUS_AMIGA: u16 = 0x16;
    pub const BUS_ADB: u16 = 0x17;
    pub const BUS_I2C: u16 = 0x18;
    pub const BUS_HOST: u16 = 0x19;
    pub const BUS_GSC: u16 = 0x1A;
    pub const BUS_ATARI: u16 = 0x1B;
    pub const BUS_SPI: u16 = 0x1C;
    pub const BUS_RMI: u16 = 0x1D;
    pub const BUS_CEC: u16 = 0x1E;
    pub const BUS_INTEL_ISHTP: u16 = 0x1F;
}

/// Input device capability bitmaps.
#[derive(Debug, Clone)]
pub struct InputCapability {
    /// Supported event types (`EV_KEY`, `EV_REL`, etc.)
    supported_event_types: EventTypes,
    /// Supported key/button codes.
    supported_keys: KeyCodeSet,
    /// Supported relative axis codes.
    supported_relative_axes: RelCodeSet,
    // TODO: Add supported_absolute_axes, supported_misc, etc.
}

impl Default for InputCapability {
    fn default() -> Self {
        Self::new()
    }
}

impl InputCapability {
    /// Creates a new empty input capability.
    pub fn new() -> Self {
        Self {
            supported_event_types: EventTypes::new(),
            supported_keys: KeyCodeSet::new(),
            supported_relative_axes: RelCodeSet::new(),
        }
    }

    /// Sets event type capability.
    pub fn set_supported_event_type(&mut self, event_type: EventTypes) {
        self.supported_event_types |= event_type;
    }

    /// Checks if an event type is supported.
    pub fn support_event_type(&self, event_type: EventTypes) -> bool {
        self.supported_event_types.contains(event_type)
    }

    /// Removes support for an event type.
    pub fn clear_supported_event_type(&mut self, event_type: EventTypes) {
        self.supported_event_types &= !event_type;
    }

    /// Sets key capability.
    pub fn set_supported_key(&mut self, key_code: KeyCode) {
        self.supported_keys.set(key_code);
        self.set_supported_event_type(EventTypes::KEY);
    }

    /// Checks if a key code is supported.
    pub fn support_key(&self, key_code: KeyCode) -> bool {
        self.supported_keys.contain(key_code)
    }

    /// Detects whether the device is keyboard-like.
    ///
    /// We follow the rules defined by Linux: a device is a keyboard if
    /// - it supports `EV_KEY`, and
    /// - it has any non-button key set (i.e., below `BTN_MISC`).
    pub fn look_like_keyboard(&self) -> bool {
        if !self.support_event_type(EventTypes::KEY) {
            return false;
        }

        self.supported_keys
            .contain_any(0..KeyCode::BtnMisc as usize)
    }

    /// Removes support for a key code.
    pub fn clear_supported_key(&mut self, key_code: KeyCode) {
        self.supported_keys.clear(key_code);
    }

    /// Sets relative axis capability.
    pub fn set_supported_relative_axis(&mut self, rel_code: RelCode) {
        self.supported_relative_axes.set(rel_code);
        self.set_supported_event_type(EventTypes::REL);
    }

    /// Checks if a relative code is supported.
    pub fn support_relative_axis(&self, rel_code: RelCode) -> bool {
        self.supported_relative_axes.contain(rel_code)
    }

    /// Removes support for a relative code.
    pub fn clear_supported_relative_axis(&mut self, rel_code: RelCode) {
        self.supported_relative_axes.clear(rel_code);
    }

    /// Returns the supported event types as a bitmap.
    pub fn event_types_bits(&self) -> u32 {
        self.supported_event_types.bits()
    }

    /// Returns the supported key code bitmap as bytes.
    pub fn supported_keys_bitmap(&self) -> &[u8] {
        self.supported_keys.as_raw_slice()
    }

    /// Returns the supported relative axes bitmap as bytes.
    pub fn supported_relative_axes_bitmap(&self) -> &[u8] {
        self.supported_relative_axes.as_raw_slice()
    }
}

pub trait InputDevice: Send + Sync + Any + Debug {
    /// Device name.
    fn name(&self) -> &str;

    /// Physical location of the device in the system topology.
    ///
    /// This string describes the physical path through which the device is connected
    /// to the system. It helps identify where the device is physically located and
    /// how it's connected (e.g., USB port, ISA bus, etc.).
    ///
    /// # Examples
    /// - `"isa0060/serio0/input0"` - i8042 keyboard connected via ISA bus
    /// - `"usb-0000:00:1d.0-1/input0"` - USB device connected to specific USB port
    fn phys(&self) -> &str;

    /// Unique identifier for the device instance.
    ///
    /// This string provides a unique identifier for the specific device instance,
    /// typically derived from device-specific information like serial numbers,
    /// MAC addresses, or other hardware-level unique identifiers.
    ///
    /// # Examples
    /// - `"00:1B:DC:0F:AC:27"` - MAC address for Bluetooth devices
    /// - `"S/N: 12345678"` - Device serial number
    /// - `""` - Empty string for devices without unique identifiers
    fn uniq(&self) -> &str;

    /// Device ID.
    fn id(&self) -> InputId;

    /// Device capabilities.
    fn capability(&self) -> &InputCapability;
}

/// Registered input device that can submit events to handlers.
#[derive(Debug)]
pub struct RegisteredInputDevice {
    /// Original device.
    device: Arc<dyn InputDevice>,
    /// Reference to bound handlers for direct event dispatch.
    handlers: Arc<RwLock<Vec<BoundInputHandler>, WriteIrqDisabled>>,
}

impl RegisteredInputDevice {
    pub(crate) fn new(
        device: Arc<dyn InputDevice>,
        handlers: Arc<RwLock<Vec<BoundInputHandler>, WriteIrqDisabled>>,
    ) -> Self {
        Self { device, handlers }
    }

    /// Submits multiple events in batch.
    pub fn submit_events(&self, events: &[InputEvent]) {
        debug_assert!(
            events.iter().all(|e| self.is_event_supported(e)),
            "Device '{}' submitted unsupported event",
            self.device.name()
        );

        let handlers = self.handlers.read();
        if handlers.is_empty() {
            log::debug!(
                "Input: dropped events from device {} because it has no handlers",
                self.device.name()
            );
            return;
        }

        for bound_handler in handlers.iter() {
            bound_handler.handler.handle_events(events);
        }
    }

    /// Gets the underlying device reference.
    pub fn device(&self) -> &Arc<dyn InputDevice> {
        &self.device
    }

    /// Counts the number of connected handlers.
    pub fn count_handlers(&self) -> usize {
        self.handlers.read().len()
    }

    /// Checks if the device supports a specific event based on its capabilities.
    fn is_event_supported(&self, event: &InputEvent) -> bool {
        let capability = self.device.capability();

        match event {
            InputEvent::Sync(_) => capability.support_event_type(EventTypes::SYN),
            InputEvent::Key(key_event, _) => {
                capability.support_event_type(EventTypes::KEY) && capability.support_key(*key_event)
            }
            InputEvent::Relative(rel_event, _) => {
                capability.support_event_type(EventTypes::REL)
                    && capability.support_relative_axis(*rel_event)
            }
        }
    }
}

impl InputCapability {
    /// Adds all standard keyboard keys to the capability.
    pub fn add_standard_keyboard_keys(&mut self) {
        let standard_keys = [
            // Function keys
            KeyCode::Esc,
            KeyCode::F1,
            KeyCode::F2,
            KeyCode::F3,
            KeyCode::F4,
            KeyCode::F5,
            KeyCode::F6,
            KeyCode::F7,
            KeyCode::F8,
            KeyCode::F9,
            KeyCode::F10,
            KeyCode::F11,
            KeyCode::F12,
            // Number row
            KeyCode::Num1,
            KeyCode::Num2,
            KeyCode::Num3,
            KeyCode::Num4,
            KeyCode::Num5,
            KeyCode::Num6,
            KeyCode::Num7,
            KeyCode::Num8,
            KeyCode::Num9,
            KeyCode::Num0,
            KeyCode::Minus,
            KeyCode::Equal,
            KeyCode::Backspace,
            // First row (QWERTY)
            KeyCode::Tab,
            KeyCode::Q,
            KeyCode::W,
            KeyCode::E,
            KeyCode::R,
            KeyCode::T,
            KeyCode::Y,
            KeyCode::U,
            KeyCode::I,
            KeyCode::O,
            KeyCode::P,
            KeyCode::LeftBrace,
            KeyCode::RightBrace,
            KeyCode::Backslash,
            // Second row (ASDF)
            KeyCode::CapsLock,
            KeyCode::A,
            KeyCode::S,
            KeyCode::D,
            KeyCode::F,
            KeyCode::G,
            KeyCode::H,
            KeyCode::J,
            KeyCode::K,
            KeyCode::L,
            KeyCode::Semicolon,
            KeyCode::Apostrophe,
            KeyCode::Enter,
            // Third row (ZXCV)
            KeyCode::LeftShift,
            KeyCode::Z,
            KeyCode::X,
            KeyCode::C,
            KeyCode::V,
            KeyCode::B,
            KeyCode::N,
            KeyCode::M,
            KeyCode::Comma,
            KeyCode::Dot,
            KeyCode::Slash,
            KeyCode::RightShift,
            // Bottom row
            KeyCode::LeftCtrl,
            KeyCode::LeftAlt,
            KeyCode::Space,
            KeyCode::RightAlt,
            KeyCode::RightCtrl,
            // Special keys
            KeyCode::Grave,
            KeyCode::LeftMeta,
            KeyCode::RightMeta,
            KeyCode::Menu,
            // Arrow keys
            KeyCode::Up,
            KeyCode::Down,
            KeyCode::Left,
            KeyCode::Right,
            // Navigation cluster
            KeyCode::Home,
            KeyCode::End,
            KeyCode::PageUp,
            KeyCode::PageDown,
            KeyCode::Insert,
            KeyCode::Delete,
            // Lock keys
            KeyCode::NumLock,
            KeyCode::ScrollLock,
            // Numpad
            KeyCode::Kp0,
            KeyCode::Kp1,
            KeyCode::Kp2,
            KeyCode::Kp3,
            KeyCode::Kp4,
            KeyCode::Kp5,
            KeyCode::Kp6,
            KeyCode::Kp7,
            KeyCode::Kp8,
            KeyCode::Kp9,
            KeyCode::KpDot,
            KeyCode::KpPlus,
            KeyCode::KpMinus,
            KeyCode::KpAsterisk,
            KeyCode::KpSlash,
            KeyCode::KpEnter,
            // Common media keys
            KeyCode::Mute,
            KeyCode::VolumeDown,
            KeyCode::VolumeUp,
        ];

        for key in standard_keys {
            self.set_supported_key(key);
        }
    }
}

impl Drop for RegisteredInputDevice {
    fn drop(&mut self) {
        unregister_device(&self.device).unwrap();
    }
}
