///|
pub fn carousel_controlled(
  id~ : String,
  items~ : @minimoon.Val[Array[Panel]],
  current~ : @minimoon.Val[Int],
  on_change~ : @minimoon.Emit[Int],
  autoplay? : Bool = false,
  circular? : Bool = false,
  vertical? : Bool = false,
  interval? : Int = 5000,
) -> @minimoon.Val[@minimoon.Node] {
  let dispatch = carousel_dispatch(
    items.map(items => items.length()),
    current,
    on_change,
    circular,
  )
  @minimoon.Val::view2(items, current, (items, current) => {
    let current = current.clamp(min=0, max=(items.length() - 1).max(0))
    ui_container("carousel", id~, [
      @minimoon.swiper(
        id=id + "-swiper",
        current~,
        autoplay~,
        circular~,
        vertical~,
        interval~,
        on_change~,
        event_key=id + "/change",
        items.map(item => @minimoon.swiper_item(item_id=item.key, item.content)),
      ),
      ui_container("carousel-controls", [
        @minimoon.button(
          disabled=items.is_empty() || (!circular && current == 0),
          event_key=id + "/previous",
          on_tap=if items.is_empty() || (!circular && current == 0) {
            @minimoon.none
          } else {
            dispatch(Step(-1))
          },
          "Previous slide",
        ),
        @minimoon.button(
          disabled=items.is_empty() ||
            (!circular && current + 1 == items.length()),
          event_key=id + "/next",
          on_tap=if items.is_empty() ||
            (!circular && current + 1 == items.length()) {
            @minimoon.none
          } else {
            dispatch(Step(1))
          },
          "Next slide",
        ),
      ]),
    ])
  })
}

///|
pub fn carousel(
  id~ : String,
  items~ : @minimoon.Val[Array[Panel]],
  autoplay? : Bool = false,
  circular? : Bool = false,
  vertical? : Bool = false,
  interval? : Int = 5000,
) -> @minimoon.Val[@minimoon.Node] {
  let (current, emit) = @minimoon.create_variable(0)
  carousel_controlled(
    id~,
    items~,
    current~,
    on_change=emit.map(value => _ => value),
    autoplay~,
    circular~,
    vertical~,
    interval~,
  )
}

///|
pub fn[C : @minimoon.IsChildren] scroll_area(
  children : C,
  id? : String = "",
  horizontal? : Bool = false,
  vertical? : Bool = true,
  height? : Int = 320,
  on_scroll? : @minimoon.Emit[@minimoon.ScrollDetail],
  on_upper? : @minimoon.Cmd,
  on_lower? : @minimoon.Cmd,
) -> @minimoon.Node {
  @minimoon.scroll_view(
    id~,
    class="mmui-scroll-area",
    scroll_x=horizontal,
    scroll_y=vertical,
    style="height:" + height.max(0).to_string() + "px;",
    on_scroll?,
    on_upper?,
    on_lower?,
    children,
  )
}

///|
pub(all) struct NavigationItem {
  key : String
  label : String
  target : @minimoon.Route
}

///|
pub fn navigation_menu(
  items : Array[NavigationItem],
  id? : String = "",
) -> @minimoon.Node {
  ui_container(
    "navigation-menu",
    id~,
    semantics=@minimoon.semantics(role=@minimoon.NavigationRole),
    items.map(item => {
      @minimoon.navigator(
        id=id + "-" + item.key,
        target=item.target,
        class="mmui-navigation-link",
        item.label,
      )
    }),
  )
}

///|
pub fn sidebar_controlled(
  id~ : String,
  content~ : @minimoon.Val[@minimoon.Node],
  collapsed~ : @minimoon.Val[Bool],
  on_change~ : @minimoon.Emit[Bool],
  label? : String = "Navigation",
  width? : Int = 256,
) -> @minimoon.Val[@minimoon.Node] {
  @minimoon.Val::view2(content, collapsed, (content, collapsed) => {
    ui_container(
      "sidebar",
      id~,
      style="width:" +
        (if collapsed { 56 } else { width.max(56) }).to_string() +
        "px;",
      semantics=@minimoon.semantics(role=@minimoon.NavigationRole, label~),
      [
        @minimoon.button(
          event_key=id + "/toggle",
          on_tap=on_change(!collapsed),
          semantics=@minimoon.semantics(expanded=!collapsed),
          if collapsed {
            "Expand"
          } else {
            "Collapse"
          },
        ),
        if collapsed {
          @minimoon.nothing()
        } else {
          content
        },
      ],
    )
  })
}

///|
pub fn sidebar(
  id~ : String,
  content~ : @minimoon.Val[@minimoon.Node],
  initially_collapsed? : Bool = false,
  label? : String = "Navigation",
  width? : Int = 256,
) -> @minimoon.Val[@minimoon.Node] {
  let (collapsed, emit) = @minimoon.create_variable(initially_collapsed)
  sidebar_controlled(
    id~,
    content~,
    collapsed~,
    on_change=emit.map(value => _ => value),
    label~,
    width~,
  )
}