/// The classification function
#[cfg(coverage)]
fn classify_device(dev: &Device) -> DeviceKind {
    let evbits = dev.supported_events();
    let keyset = dev.supported_keys();

    if evbits.contains(EventType::KEY)
        && keyset
            .is_some_and(|keys| keys.contains(KeyCode::KEY_A) || keys.contains(KeyCode::KEY_ENTER))
    {
        if should_ignore_keyboard_device(dev) {
            return DeviceKind::Other;
        }
        return DeviceKind::Keyboard;
    }

    if evbits.contains(EventType::RELATIVE)
        && let (Some(rel), Some(keys)) = (dev.supported_relative_axes(), keyset)
        && rel.contains(RelativeAxisCode::REL_X)
        && rel.contains(RelativeAxisCode::REL_Y)
        && (keys.contains(KeyCode::BTN_LEFT) || keys.contains(KeyCode::BTN_RIGHT))
    {
        return DeviceKind::Mouse;
    }

    if evbits.contains(EventType::ABSOLUTE)
        && let (Some(abs), Some(keys)) = (dev.supported_absolute_axes(), keyset)
        && ((abs.contains(AbsoluteAxisCode::ABS_X) && abs.contains(AbsoluteAxisCode::ABS_Y))
            || (abs.contains(AbsoluteAxisCode::ABS_MT_POSITION_X)
                && abs.contains(AbsoluteAxisCode::ABS_MT_POSITION_Y)))
        && (keys.contains(KeyCode::BTN_TOUCH) || keys.contains(KeyCode::BTN_LEFT))
    {
        return DeviceKind::Mouse;
    }

    DeviceKind::Other
}

#[cfg(not(coverage))]
fn classify_device(dev: &Device) -> DeviceKind {
    let evbits = dev.supported_events();

    // Keyboard logic
    if evbits.contains(EventType::KEY)
        && let Some(keys) = dev.supported_keys()
            && (keys.contains(KeyCode::KEY_A) || keys.contains(KeyCode::KEY_ENTER)) {
                if should_ignore_keyboard_device(dev) {
                    return DeviceKind::Other;
                }
                return DeviceKind::Keyboard;
            }

    // Mouse logic (relative)
    if evbits.contains(EventType::RELATIVE)
        && let (Some(rel), Some(keys)) = (dev.supported_relative_axes(), dev.supported_keys()) {
            let has_xy =
                rel.contains(RelativeAxisCode::REL_X) && rel.contains(RelativeAxisCode::REL_Y);
            let has_btn = keys.contains(KeyCode::BTN_LEFT) || keys.contains(KeyCode::BTN_RIGHT);
            if has_xy && has_btn {
                return DeviceKind::Mouse;
            }
        }
    // Touchpad logic (absolute)
    if evbits.contains(EventType::ABSOLUTE)
        && let (Some(abs), Some(keys)) = (dev.supported_absolute_axes(), dev.supported_keys()) {
            let has_xy = (abs.contains(AbsoluteAxisCode::ABS_X)
                && abs.contains(AbsoluteAxisCode::ABS_Y))
                || (abs.contains(AbsoluteAxisCode::ABS_MT_POSITION_X)
                    && abs.contains(AbsoluteAxisCode::ABS_MT_POSITION_Y));
            let has_btn = keys.contains(KeyCode::BTN_TOUCH) || keys.contains(KeyCode::BTN_LEFT);
            if has_xy && has_btn {
                return DeviceKind::Mouse;
            }
        }

    DeviceKind::Other
}

/// Internal enum for device classification
#[derive(Debug, Clone, Copy)]
enum DeviceKind {
    Keyboard,
    Mouse,
    Other,
}

fn should_ignore_keyboard_device(dev: &Device) -> bool {
    let name = dev.name().unwrap_or_default().to_ascii_lowercase();
    name.contains("lesavka")
        || name.contains("automation input")
        || name.contains("codex-persistent-kbd")
}

fn update_shadow_pressed_keys(pressed_keys: &mut HashSet<KeyCode>, code: KeyCode, value: i32) {
    if value == 0 {
        pressed_keys.remove(&code);
    } else if value > 0 {
        pressed_keys.insert(code);
    }
}
