//! Button-to-USB mapping for CMDR Joystick
//!
//! This module defines the hardware button indices (matrix layout and extras)
//! and their mapping to USB joystick button numbers and HAT directions.
//! The mapping is consumed by the button processing and USB report layers.
//!
//! Notes
//! - USB buttons are 1-based (USB_BUTTON_1..=USB_BUTTON_32)
//! - HAT is represented by four symbolic constants: up/right/down/left
//! - Some buttons enable a “long press” variant via `usb_button_long`

// HW Button index map:
// ---------------------------------------------------------------
// |  0 L|  1 U| 25 U |        |  2  |        | 26 U |  4 U|  3 L|
// ---------------------------------------------------------------
// |     |  5  |  6  |  7  |             | 12  | 11  | 10  |     |
// |                                                             |
// |                 |  8  |             | 13  |                 |
// |                 |  9  |             | 14  |                 |
// |      X1/Y1                                       X2/Y2      |
// |                 | 16  |             | 21  |                 |
// |           | 19  | 15  | 17  | | 24  | 20  | 22  |           |
// |                 | 18  |             | 23  |                 |
// ---------------------------------------------------------------

// ==================== BUTTON INDICES ====================
pub const BUTTON_FRONT_LEFT_LOWER: usize = 0;
pub const BUTTON_FRONT_LEFT_UPPER: usize = 1;
pub const BUTTON_FRONT_LEFT_EXTRA: usize = 25;
pub const BUTTON_FRONT_CONFIG: usize = 2;
pub const BUTTON_FRONT_RIGHT_LOWER: usize = 3;
pub const BUTTON_FRONT_RIGHT_UPPER: usize = 4;
pub const BUTTON_FRONT_RIGHT_EXTRA: usize = 26;
pub const BUTTON_TOP_LEFT_LOW: usize = 5;
pub const BUTTON_TOP_LEFT_HIGH: usize = 6;
pub const BUTTON_TOP_LEFT_MODE: usize = 7;
pub const BUTTON_TOP_LEFT_UP: usize = 8;
pub const BUTTON_TOP_LEFT_DOWN: usize = 9;
pub const BUTTON_TOP_LEFT_HAT: usize = 15;
pub const BUTTON_TOP_LEFT_HAT_UP: usize = 16;
pub const BUTTON_TOP_LEFT_HAT_RIGHT: usize = 17;
pub const BUTTON_TOP_LEFT_HAT_DOWN: usize = 18;
pub const BUTTON_TOP_LEFT_HAT_LEFT: usize = 19;
pub const BUTTON_TOP_RIGHT_LOW: usize = 10;
pub const BUTTON_TOP_RIGHT_HIGH: usize = 11;
pub const BUTTON_TOP_RIGHT_MODE: usize = 12;
pub const BUTTON_TOP_RIGHT_UP: usize = 13;
pub const BUTTON_TOP_RIGHT_DOWN: usize = 14;
pub const BUTTON_TOP_RIGHT_HAT: usize = 20;
pub const BUTTON_TOP_RIGHT_HAT_UP: usize = 21;
pub const BUTTON_TOP_RIGHT_HAT_RIGHT: usize = 22;
pub const BUTTON_TOP_RIGHT_HAT_DOWN: usize = 23;
pub const BUTTON_TOP_RIGHT_HAT_LEFT: usize = 24;

// ==================== USB BUTTON MAPPING ====================
pub const USB_BUTTON_1: usize = 1;
pub const USB_BUTTON_2: usize = 2;
pub const USB_BUTTON_3: usize = 3;
pub const USB_BUTTON_4: usize = 4;
pub const USB_BUTTON_5: usize = 5;
pub const USB_BUTTON_6: usize = 6;
pub const USB_BUTTON_7: usize = 7;
pub const USB_BUTTON_8: usize = 8;
pub const USB_BUTTON_9: usize = 9;
pub const USB_BUTTON_10: usize = 10;
pub const USB_BUTTON_11: usize = 11;
pub const USB_BUTTON_12: usize = 12;
pub const USB_BUTTON_13: usize = 13;
pub const USB_BUTTON_14: usize = 14;
pub const USB_BUTTON_15: usize = 15;
pub const USB_BUTTON_16: usize = 16;
pub const USB_BUTTON_17: usize = 17;
pub const USB_BUTTON_18: usize = 18;
pub const USB_BUTTON_19: usize = 19;
pub const USB_BUTTON_20: usize = 20;
pub const USB_BUTTON_21: usize = 21;
pub const USB_BUTTON_22: usize = 22;
pub const USB_BUTTON_23: usize = 23;
pub const USB_BUTTON_24: usize = 24;
pub const USB_BUTTON_25: usize = 25;
pub const USB_BUTTON_26: usize = 26;
pub const USB_BUTTON_27: usize = 27;
pub const USB_BUTTON_28: usize = 28;
pub const USB_BUTTON_29: usize = 29;
pub const USB_BUTTON_30: usize = 30;
pub const USB_BUTTON_31: usize = 31;
pub const USB_BUTTON_32: usize = 32;

pub const USB_HAT_UP: usize = 33;
pub const USB_HAT_RIGHT: usize = 34;
pub const USB_HAT_DOWN: usize = 35;
pub const USB_HAT_LEFT: usize = 36;

use crate::buttons::Button;

/// Configure USB button mappings for all buttons.
///
/// Populates per-button fields used by the button state machine:
/// - `usb_button`: regular (short-press) USB button assignment
/// - `usb_button_long`: long-press USB button assignment (if enabled)
/// - `enable_long_press` and `enable_long_hold`: behavior flags for timing
pub fn configure_button_mappings(buttons: &mut [Button]) {
    buttons[BUTTON_FRONT_LEFT_LOWER].usb_button = USB_BUTTON_29;
    buttons[BUTTON_FRONT_LEFT_UPPER].usb_button = USB_BUTTON_28;
    buttons[BUTTON_FRONT_CONFIG].usb_button = USB_BUTTON_32; // Button used as global config.
    buttons[BUTTON_FRONT_CONFIG].usb_button_long = USB_BUTTON_3;
    buttons[BUTTON_FRONT_CONFIG].enable_long_press = true;

    buttons[BUTTON_FRONT_RIGHT_LOWER].usb_button = USB_BUTTON_2;
    buttons[BUTTON_FRONT_RIGHT_UPPER].usb_button = USB_BUTTON_1;
    buttons[BUTTON_TOP_LEFT_LOW].usb_button = USB_BUTTON_4;
    buttons[BUTTON_TOP_LEFT_LOW].usb_button_long = USB_BUTTON_5;
    buttons[BUTTON_TOP_LEFT_LOW].enable_long_press = true;
    buttons[BUTTON_TOP_LEFT_LOW].enable_long_hold = true;

    buttons[BUTTON_TOP_LEFT_HIGH].usb_button = USB_BUTTON_6;
    buttons[BUTTON_TOP_LEFT_HIGH].usb_button_long = USB_BUTTON_7;
    buttons[BUTTON_TOP_LEFT_HIGH].enable_long_press = true;

    buttons[BUTTON_TOP_LEFT_MODE].usb_button = 0;
    buttons[BUTTON_TOP_LEFT_UP].usb_button = USB_BUTTON_12;
    buttons[BUTTON_TOP_LEFT_UP].usb_button_long = USB_BUTTON_13;
    buttons[BUTTON_TOP_LEFT_UP].enable_long_press = true;

    buttons[BUTTON_TOP_LEFT_DOWN].usb_button = USB_BUTTON_16;
    buttons[BUTTON_TOP_LEFT_DOWN].usb_button_long = USB_BUTTON_17;
    buttons[BUTTON_TOP_LEFT_DOWN].enable_long_press = true;
    buttons[BUTTON_TOP_LEFT_DOWN].enable_long_hold = true;

    buttons[BUTTON_TOP_RIGHT_LOW].usb_button = USB_BUTTON_10;
    buttons[BUTTON_TOP_RIGHT_LOW].usb_button_long = USB_BUTTON_11;
    buttons[BUTTON_TOP_RIGHT_LOW].enable_long_press = true;

    buttons[BUTTON_TOP_RIGHT_HIGH].usb_button = USB_BUTTON_8;
    buttons[BUTTON_TOP_RIGHT_HIGH].usb_button_long = USB_BUTTON_9;
    buttons[BUTTON_TOP_RIGHT_HIGH].enable_long_press = true;

    buttons[BUTTON_TOP_RIGHT_MODE].usb_button = 0;
    buttons[BUTTON_TOP_RIGHT_UP].usb_button = USB_BUTTON_14;
    buttons[BUTTON_TOP_RIGHT_UP].usb_button_long = USB_BUTTON_15;
    buttons[BUTTON_TOP_RIGHT_UP].enable_long_press = true;

    buttons[BUTTON_TOP_RIGHT_DOWN].usb_button = USB_BUTTON_18;
    buttons[BUTTON_TOP_RIGHT_DOWN].usb_button_long = USB_BUTTON_19;
    buttons[BUTTON_TOP_RIGHT_DOWN].enable_long_press = true;

    buttons[BUTTON_TOP_LEFT_HAT].usb_button = USB_BUTTON_20;
    buttons[BUTTON_TOP_LEFT_HAT].usb_button_long = USB_BUTTON_21;
    buttons[BUTTON_TOP_LEFT_HAT].enable_long_press = true;

    buttons[BUTTON_TOP_LEFT_HAT_UP].usb_button = USB_BUTTON_22;
    buttons[BUTTON_TOP_LEFT_HAT_RIGHT].usb_button = USB_BUTTON_23;
    buttons[BUTTON_TOP_LEFT_HAT_DOWN].usb_button = USB_BUTTON_24;
    buttons[BUTTON_TOP_LEFT_HAT_LEFT].usb_button = USB_BUTTON_25;
    buttons[BUTTON_TOP_RIGHT_HAT].usb_button = USB_BUTTON_26;
    buttons[BUTTON_TOP_RIGHT_HAT].usb_button_long = USB_BUTTON_27;
    buttons[BUTTON_TOP_RIGHT_HAT].enable_long_press = true;

    buttons[BUTTON_TOP_RIGHT_HAT_UP].usb_button = USB_HAT_UP;
    buttons[BUTTON_TOP_RIGHT_HAT_RIGHT].usb_button = USB_HAT_RIGHT;
    buttons[BUTTON_TOP_RIGHT_HAT_DOWN].usb_button = USB_HAT_DOWN;
    buttons[BUTTON_TOP_RIGHT_HAT_LEFT].usb_button = USB_HAT_LEFT;
    buttons[BUTTON_FRONT_LEFT_EXTRA].usb_button = USB_BUTTON_30;
    buttons[BUTTON_FRONT_RIGHT_EXTRA].usb_button = USB_BUTTON_31;
}

#[cfg(all(test, feature = "std"))]
mod tests {
    use super::*;
    use crate::buttons::{Button, TOTAL_BUTTONS};

    #[test]
    fn front_buttons_have_expected_mappings() {
        // Front panel buttons map to the expected USB button ids.
        let mut buttons = [Button::default(); TOTAL_BUTTONS];
        configure_button_mappings(&mut buttons);

        assert_eq!(buttons[BUTTON_FRONT_LEFT_LOWER].usb_button, USB_BUTTON_29);
        assert_eq!(buttons[BUTTON_FRONT_RIGHT_UPPER].usb_button, USB_BUTTON_1);
        assert_eq!(buttons[BUTTON_FRONT_CONFIG].usb_button_long, USB_BUTTON_3);
    }

    #[test]
    fn long_press_flags_set_correctly() {
        // Long-press flags are configured for buttons that need them at runtime.
        let mut buttons = [Button::default(); TOTAL_BUTTONS];
        configure_button_mappings(&mut buttons);

        assert!(buttons[BUTTON_TOP_LEFT_LOW].enable_long_press);
        assert!(buttons[BUTTON_TOP_LEFT_LOW].enable_long_hold);
        assert!(buttons[BUTTON_TOP_RIGHT_LOW].enable_long_press);
        assert!(!buttons[BUTTON_TOP_RIGHT_LOW].enable_long_hold);
    }

    #[test]
    fn hat_buttons_map_to_expected_ids() {
        // Hat direction buttons should map to the numerical HID hat constants.
        let mut buttons = [Button::default(); TOTAL_BUTTONS];
        configure_button_mappings(&mut buttons);

        assert_eq!(buttons[BUTTON_TOP_RIGHT_HAT_UP].usb_button, USB_HAT_UP);
        assert_eq!(
            buttons[BUTTON_TOP_RIGHT_HAT_RIGHT].usb_button,
            USB_HAT_RIGHT
        );
        assert_eq!(buttons[BUTTON_TOP_RIGHT_HAT_DOWN].usb_button, USB_HAT_DOWN);
        assert_eq!(buttons[BUTTON_TOP_RIGHT_HAT_LEFT].usb_button, USB_HAT_LEFT);
    }
}
