///|
/// APG Menu Button Pattern
/// https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/
///
/// A menu button is a button that opens a menu. It is often styled
/// as a typical push button with a downward pointing arrow.
///
/// Keyboard Interaction:
/// - Enter/Space: Open menu, move focus to first item
/// - Down Arrow: Open menu, move focus to first item
/// - Up Arrow: Open menu, move focus to last item
/// - Escape: Close menu, return focus to button
///
/// Menu Navigation:
/// - Down Arrow: Move to next item (wrap to first)
/// - Up Arrow: Move to previous item (wrap to last)
/// - Home: Move to first item
/// - End: Move to last item
/// - Enter/Space: Activate item, close menu
/// - Escape: Close menu
/// - Character: Move to item starting with that character
///
/// ARIA:
/// - Button: aria-haspopup="menu", aria-expanded, aria-controls
/// - Menu: role="menu", aria-labelledby
/// - Menu items: role="menuitem", tabindex

///|
/// Menu item data
pub(all) struct MenuItem {
  id : String
  label : String
  disabled : Bool
}

///|
/// Create a menu item
pub fn menu_item(id : String, label : String, disabled? : Bool) -> MenuItem {
  { id, label, disabled: disabled.unwrap_or(false) }
}

///|
/// Create a menu button trigger with ID.
/// Uses existing menu_button from button.mbt internally.
///
/// Parameters:
/// - id: Button ID
/// - expanded: Whether menu is open
/// - menu_id: ID of the menu element
/// - aria_label: Accessible label
/// - on_click: Click handler
/// - on_keydown: Keydown handler
/// - children: Button content
pub fn[E] menu_trigger(
  id : String,
  expanded : Bool,
  menu_id : String,
  aria_label? : String,
  on_click? : @luna.EventHandler[E],
  on_keydown? : @luna.EventHandler[E],
  children : Array[@luna.Node[E, String]],
) -> @luna.Node[E, String] {
  let attrs : Array[(String, @luna.Attr[E, String])] = [
    ("type", @luna.attr_static("button")),
    ("id", @luna.attr_static(id)),
    ("aria-haspopup", @luna.attr_static("menu")),
    (
      "aria-expanded",
      @luna.attr_static(if expanded { "true" } else { "false" }),
    ),
    ("aria-controls", @luna.attr_static(menu_id)),
  ]
  if aria_label is Some(label) {
    attrs.push(("aria-label", @luna.attr_static(label)))
  }
  if on_click is Some(handler) {
    attrs.push(("click", @luna.attr_handler(handler)))
  }
  if on_keydown is Some(handler) {
    attrs.push(("keydown", @luna.attr_handler(handler)))
  }
  @luna.h("button", attrs) <| children
}

///|
/// Create a dynamic menu trigger with signal-based state.
pub fn[E] menu_trigger_dyn(
  id : String,
  expanded : @resource.Signal[Bool],
  menu_id : String,
  aria_label? : String,
  on_click? : @luna.EventHandler[E],
  on_keydown? : @luna.EventHandler[E],
  children : Array[@luna.Node[E, String]],
) -> @luna.Node[E, String] {
  let attrs : Array[(String, @luna.Attr[E, String])] = [
    ("type", @luna.attr_static("button")),
    ("id", @luna.attr_static(id)),
    ("aria-haspopup", @luna.attr_static("menu")),
    (
      "aria-expanded",
      @luna.attr_dynamic(fn() { if expanded.get() { "true" } else { "false" } }),
    ),
    ("aria-controls", @luna.attr_static(menu_id)),
  ]
  if aria_label is Some(label) {
    attrs.push(("aria-label", @luna.attr_static(label)))
  }
  if on_click is Some(handler) {
    attrs.push(("click", @luna.attr_handler(handler)))
  }
  if on_keydown is Some(handler) {
    attrs.push(("keydown", @luna.attr_handler(handler)))
  }
  @luna.h("button", attrs) <| children
}

///|
/// Create a menu container.
///
/// Parameters:
/// - id: Menu ID (referenced by button's aria-controls)
/// - labelled_by: ID of the button that labels this menu
/// - visible: Whether menu is visible
/// - children: Menu items
pub fn[E] menu(
  id : String,
  labelled_by : String,
  visible : Bool,
  children : Array[@luna.Node[E, String]],
) -> @luna.Node[E, String] {
  let attrs : Array[(String, @luna.Attr[E, String])] = [
    ("role", @luna.attr_static("menu")),
    ("id", @luna.attr_static(id)),
    ("aria-labelledby", @luna.attr_static(labelled_by)),
  ]
  if !visible {
    attrs.push(("hidden", @luna.attr_static("")))
  }
  @luna.h("ul", attrs) <| children
}

///|
/// Create a dynamic menu with signal-based visibility.
pub fn[E] menu_dyn(
  id : String,
  labelled_by : String,
  visible : @resource.Signal[Bool],
  children : Array[@luna.Node[E, String]],
) -> @luna.Node[E, String] {
  let attrs : Array[(String, @luna.Attr[E, String])] = [
    ("role", @luna.attr_static("menu")),
    ("id", @luna.attr_static(id)),
    ("aria-labelledby", @luna.attr_static(labelled_by)),
  ]
  @luna.show(fn() { visible.get() }, fn() { @luna.h("ul", attrs) <| children })
}

///|
/// Create a menu item element.
///
/// Parameters:
/// - id: Item ID
/// - selected: Whether this item has focus (tabindex=0)
/// - disabled: Whether item is disabled
/// - on_click: Click handler
/// - on_keydown: Keydown handler
/// - children: Item content
pub fn[E] menuitem(
  id? : String,
  selected : Bool,
  disabled? : Bool,
  on_click? : @luna.EventHandler[E],
  on_keydown? : @luna.EventHandler[E],
  children : Array[@luna.Node[E, String]],
) -> @luna.Node[E, String] {
  let is_disabled = disabled.unwrap_or(false)
  let attrs : Array[(String, @luna.Attr[E, String])] = [
    ("role", @luna.attr_static("menuitem")),
    ("tabindex", @luna.attr_static(if selected { "0" } else { "-1" })),
  ]
  if id is Some(i) {
    attrs.push(("id", @luna.attr_static(i)))
  }
  if is_disabled {
    attrs.push(("aria-disabled", @luna.attr_static("true")))
  }
  if on_click is Some(handler) {
    if !is_disabled {
      attrs.push(("click", @luna.attr_handler(handler)))
    }
  }
  if on_keydown is Some(handler) {
    attrs.push(("keydown", @luna.attr_handler(handler)))
  }
  @luna.h("li", attrs) <| children
}

///|
/// Create a dynamic menu item with signal-based selection.
pub fn[E] menuitem_dyn(
  id? : String,
  selected_index : @resource.Signal[Int],
  index : Int,
  disabled? : Bool,
  on_click? : @luna.EventHandler[E],
  on_keydown? : @luna.EventHandler[E],
  children : Array[@luna.Node[E, String]],
) -> @luna.Node[E, String] {
  let is_disabled = disabled.unwrap_or(false)
  let attrs : Array[(String, @luna.Attr[E, String])] = [
    ("role", @luna.attr_static("menuitem")),
    (
      "tabindex",
      @luna.attr_dynamic(fn() {
        if selected_index.get() == index {
          "0"
        } else {
          "-1"
        }
      }),
    ),
  ]
  if id is Some(i) {
    attrs.push(("id", @luna.attr_static(i)))
  }
  if is_disabled {
    attrs.push(("aria-disabled", @luna.attr_static("true")))
  }
  if on_click is Some(handler) {
    if !is_disabled {
      attrs.push(("click", @luna.attr_handler(handler)))
    }
  }
  if on_keydown is Some(handler) {
    attrs.push(("keydown", @luna.attr_handler(handler)))
  }
  @luna.h("li", attrs) <| children
}

///|
/// Create a menu button keyboard handler for the trigger button.
/// Handles Enter, Space, ArrowDown, ArrowUp to open menu.
pub fn make_menu_button_handler(
  is_open : () -> Bool,
  open_menu : () -> Unit,
  close_menu : () -> Unit,
  focus_first : () -> Unit,
  focus_last : () -> Unit,
) -> @luna.EventHandler[@js.Any] {
  @luna.handler(fn(e : @js.Any) {
    let key : String = e._get("key").cast()
    match key {
      "Enter" | " " | "ArrowDown" => {
        let _ = e._call("preventDefault", [])
        if !is_open() {
          open_menu()
          focus_first()
        }
      }
      "ArrowUp" => {
        let _ = e._call("preventDefault", [])
        if !is_open() {
          open_menu()
          focus_last()
        }
      }
      "Escape" => if is_open() { close_menu() }
      _ => ()
    }
  })
}

///|
/// Create a menu keyboard handler for menu items.
/// Handles arrow navigation, Enter/Space activation, Escape to close.
pub fn make_menu_nav_handler(
  current_index : () -> Int,
  item_count : Int,
  on_select : (Int) -> Unit,
  close_menu : () -> Unit,
  on_activate : (Int) -> Unit,
) -> @luna.EventHandler[@js.Any] {
  @luna.handler(fn(e : @js.Any) {
    let key : String = e._get("key").cast()
    let curr = current_index()
    match key {
      "ArrowDown" => {
        let _ = e._call("preventDefault", [])
        let next = if curr >= item_count - 1 { 0 } else { curr + 1 }
        on_select(next)
      }
      "ArrowUp" => {
        let _ = e._call("preventDefault", [])
        let next = if curr <= 0 { item_count - 1 } else { curr - 1 }
        on_select(next)
      }
      "Home" => {
        let _ = e._call("preventDefault", [])
        on_select(0)
      }
      "End" => {
        let _ = e._call("preventDefault", [])
        on_select(item_count - 1)
      }
      "Enter" | " " => {
        let _ = e._call("preventDefault", [])
        on_activate(curr)
        close_menu()
      }
      "Escape" => {
        let _ = e._call("preventDefault", [])
        close_menu()
      }
      _ => ()
    }
  })
}

///|
/// Create a complete interactive menu button with keyboard support.
///
/// Parameters:
/// - id: Base ID for the component
/// - items: Menu items
/// - on_select: Called when an item is selected
/// - button_content: Content for the trigger button
pub fn menu_button_interactive(
  id : String,
  items : Array[MenuItem],
  on_select : (String) -> Unit,
  button_content : Array[@luna.Node[@js.Any, String]],
) -> @luna.Node[@js.Any, String] {
  let open = @resource.signal(false)
  let focused_index = @resource.signal(0)
  let button_id = id + "-button"
  let menu_id = id + "-menu"
  let item_count = items.length()
  // Focus management helper
  let focus_item = fn(idx : Int) {
    focused_index.set(idx)
    let doc = @js.global_this()._get("document")
    let item_id = id + "-item-" + idx.to_string()
    let el = doc._call("getElementById", [@js.any(item_id)])
    let _ = el._call("focus", [])
  }
  let focus_button = fn() {
    let doc = @js.global_this()._get("document")
    let el = doc._call("getElementById", [@js.any(button_id)])
    let _ = el._call("focus", [])
  }
  let close_and_focus_button = fn() {
    open.set(false)
    focus_button()
  }
  // Button keydown handler
  let button_keydown = make_menu_button_handler(
    fn() { open.get() },
    fn() { open.set(true) },
    close_and_focus_button,
    fn() { focus_item(0) },
    fn() { focus_item(item_count - 1) },
  )
  // Menu keydown handler
  let menu_keydown = make_menu_nav_handler(
    fn() { focused_index.get() },
    item_count,
    focus_item,
    close_and_focus_button,
    fn(idx) {
      let item = items[idx]
      if !item.disabled {
        on_select(item.id)
      }
    },
  )
  // Build menu items
  let menu_items : Array[@luna.Node[@js.Any, String]] = []
  for i, item in items {
    let idx = i
    let item_id = id + "-item-" + i.to_string()
    menu_items.push(
      menuitem_dyn(
        id=item_id,
        focused_index,
        idx,
        disabled=item.disabled,
        on_click=@luna.handler(fn(_) {
          if !item.disabled {
            on_select(item.id)
            close_and_focus_button()
          }
        }),
        on_keydown=menu_keydown,
      ) <| [
        @luna.text(item.label),
      ],
    )
  }
  @luna.h("div", [("class", @luna.attr_static("menu-button-container"))]) <| [
    menu_trigger_dyn(
      button_id,
      open,
      menu_id,
      on_click=@luna.handler(fn(_) { open.set(!open.get()) }),
      on_keydown=button_keydown,
    ) <| button_content,
    menu_dyn(menu_id, button_id, open) <| menu_items,
  ]
}