// Sidebar -- a vertical navigation rail that becomes a drawer on small screens.
//
//   <Sidebar items='[{"label":"Dashboard","href":"/","value":"dash"}]' active="dash" />
//
// An entry is one of three shapes:
//   { label, href, value }            a single link
//   { heading, items: [...] }         a labelled group
//   { label, items: [...] }           a collapsible branch, nested to 3 levels
//
// The off-canvas presentation is Drawer rather than a second implementation,
// so the focus trap and the body scroll lock come from one place.
//
// NOTE: the style block uses /* */ comments only -- // is not a CSS comment
// and silently swallows the rule that follows it.
import Drawer from "./Drawer.wrn"

component Sidebar {
  outputs {
    toggle(payload: { open: boolean })
    open(payload: { sourceEvent: Event })
    close(payload: { source: string })
    select(payload: { item: object; value: string; level: number })
  }

  props {
    color: string = "primary"
    size: string = "default"
    label: string = "Sidebar"
    items: unknown[] = []
    active: string = ""
    mobileLabel: string = "Open navigation"
    drawerTitle: string = "Navigation"
    class: string = ""
  }

  state drawerOpen = false

  functions {
    shared function entryList() {
      return Array.isArray(items) ? items : []
    }

    // Accepts children as well as items: children is what shipped in 0.8.5
    // and existing callers should keep working.
    shared function childrenOf(entry) {
      if (!entry) {
        return []
      }
      if (Array.isArray(entry.items)) {
        return entry.items
      }
      return Array.isArray(entry.children) ? entry.children : []
    }

    shared function isGroup(entry) {
      return Boolean(entry.heading)
    }

    shared function isActive(entry) {
      return Boolean(entry.value) && entry.value === active
    }

    client function choose(entry, level) {
      if (entry.disabled) {
        return
      }
      output.select({ item: entry, value: entry.value || "", level: level })
      if (drawerOpen) {
        drawerOpen = false
        output.close({ source: "select" })
      }
    }

    client function openDrawer(sourceEvent) {
      drawerOpen = true
      output.open({ sourceEvent: sourceEvent })
      output.toggle({ open: true })
    }

    client function closeDrawer() {
      drawerOpen = false
      output.close({ source: "drawer" })
      output.toggle({ open: false })
    }
  }

  view {
    <div
      {...attrs}
      data-ui-component="Sidebar"
      class='wrn-sidebar {class}'
      data-color='{color}'
      data-size='{size}'
    >
      <button
        type="button"
        class="wrn-sidebar__launcher"
        aria-label='{mobileLabel}'
        aria-expanded='{drawerOpen}'
        @click='openDrawer(event)'
      >
        <span class="wrn-sidebar__launcher-bar" aria-hidden="true"></span>
        <span class="wrn-sidebar__launcher-text">{mobileLabel}</span>
      </button>

      <nav class="wrn-sidebar__rail" aria-label='{label}'>
        <ul class="wrn-sidebar__list" data-wrn-roving="vertical">
          {#each entryList() as entry}
            <li class="wrn-sidebar__entry" data-group='{isGroup(entry)}'>
              <p class="wrn-sidebar__heading" data-show="entry.heading">{entry.heading}</p>

              <a
                class="wrn-sidebar__link"
                data-show="!entry.heading"
                href='{entry.href || "#"}'
                data-wrn-roving-item="true"
                data-active='{isActive(entry)}'
                aria-current='{isActive(entry) ? "page" : "false"}'
                aria-disabled='{entry.disabled ? "true" : "false"}'
                @click='choose(entry, 1)'
              >
                <span
                  class='wrn-sidebar__icon {entry.icon}'
                  data-show="entry.icon"
                  aria-hidden="true"
                ></span>
                <span class="wrn-sidebar__label">{entry.label}</span>
                <span class="wrn-sidebar__badge" data-show="entry.badge">{entry.badge}</span>
              </a>

              <ul class="wrn-sidebar__sublist" data-show="childrenOf(entry).length > 0">
                {#each childrenOf(entry) as child}
                  <li class="wrn-sidebar__entry">
                    <a
                      class="wrn-sidebar__link"
                      href='{child.href || "#"}'
                      data-active='{isActive(child)}'
                      aria-current='{isActive(child) ? "page" : "false"}'
                      aria-disabled='{child.disabled ? "true" : "false"}'
                      @click='choose(child, 2)'
                    >
                      <span
                        class='wrn-sidebar__icon {child.icon}'
                        data-show="child.icon"
                        aria-hidden="true"
                      ></span>
                      <span class="wrn-sidebar__label">{child.label}</span>
                      <span class="wrn-sidebar__badge" data-show="child.badge">{child.badge}</span>
                    </a>

                    <ul
                      class="wrn-sidebar__sublist wrn-sidebar__sublist--level3"
                      data-show="childrenOf(child).length > 0"
                    >
                      {#each childrenOf(child) as leaf}
                        <li class="wrn-sidebar__entry">
                          <a
                            class="wrn-sidebar__link"
                            href='{leaf.href || "#"}'
                            data-active='{isActive(leaf)}'
                            aria-current='{isActive(leaf) ? "page" : "false"}'
                            @click='choose(leaf, 3)'
                          >
                            <span class="wrn-sidebar__label">{leaf.label}</span>
                          </a>
                        </li>
                      {/each}
                    </ul>
                  </li>
                {/each}
              </ul>
            </li>
          {/each}
        </ul>
        <slot />
      </nav>

      <Drawer
        open={drawerOpen}
        placement="left"
        title={drawerTitle}
        label={label}
        @close="closeDrawer()"
      >
        <slot name="drawer"></slot>
      </Drawer>
    </div>
  }

  style {
    .wrn-sidebar {
      --sidebar-accent: var(--wrn-color-primary);
      max-width: 100%;
    }

    .wrn-sidebar[data-color="secondary"] {
      --sidebar-accent: var(--wrn-color-secondary);
    }

    .wrn-sidebar[data-color="success"] {
      --sidebar-accent: var(--wrn-color-success);
    }

    .wrn-sidebar[data-color="danger"] {
      --sidebar-accent: var(--wrn-color-danger);
    }

    .wrn-sidebar[data-color="info"] {
      --sidebar-accent: var(--wrn-color-info);
    }

    .wrn-sidebar[data-size="sm"] {
      font-size: 0.82rem;
    }

    .wrn-sidebar[data-size="lg"] {
      font-size: 1rem;
    }

    .wrn-sidebar__rail {
      width: 100%;
    }

    .wrn-sidebar__list,
    .wrn-sidebar__sublist {
      display: grid;
      gap: 0.1rem;
      margin: 0;
      padding: 0;
      list-style: none;
    }

    .wrn-sidebar__sublist {
      margin-left: 0.85rem;
      padding-left: 0.5rem;
      border-left: 1px solid var(--wrn-color-border);
    }

    .wrn-sidebar__entry[data-group="true"] + .wrn-sidebar__entry {
      margin-top: 0.35rem;
    }

    .wrn-sidebar__heading {
      margin: 0.9rem 0 0.35rem;
      color: var(--wrn-color-text-muted);
      font-size: 0.7rem;
      font-weight: 700;
      letter-spacing: 0.08em;
      text-transform: uppercase;
    }

    .wrn-sidebar__link {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      padding: 0.45rem 0.6rem;
      border-radius: var(--wrn-radius-sm);
      color: var(--wrn-color-text-muted);
      font-size: 0.88rem;
      font-weight: 600;
      text-decoration: none;
    }

    .wrn-sidebar__link:hover {
      background: var(--wrn-color-surface-soft);
      color: var(--wrn-color-text);
    }

    .wrn-sidebar__link:focus-visible {
      outline: 2px solid var(--sidebar-accent);
      outline-offset: 2px;
    }

    .wrn-sidebar__link[data-active="true"] {
      background: color-mix(in srgb, var(--sidebar-accent) 16%, transparent);
      color: var(--sidebar-accent);
    }

    .wrn-sidebar__link[aria-disabled="true"] {
      opacity: 0.5;
      pointer-events: none;
    }

    .wrn-sidebar__label {
      min-width: 0;
    }

    .wrn-sidebar__badge {
      margin-left: auto;
      padding: 0.05rem 0.4rem;
      border-radius: 999px;
      background: color-mix(in srgb, var(--sidebar-accent) 16%, transparent);
      color: var(--sidebar-accent);
      font-size: 0.72rem;
    }

    .wrn-sidebar__launcher {
      display: none;
      align-items: center;
      gap: 0.5rem;
      padding: 0.45rem 0.7rem;
      border: 1px solid var(--wrn-color-border);
      border-radius: var(--wrn-radius-sm);
      background: var(--wrn-color-surface);
      color: var(--wrn-color-text);
      font: inherit;
      font-size: 0.9rem;
      cursor: pointer;
    }

    .wrn-sidebar__launcher-bar {
      width: 1rem;
      height: 2px;
      background: currentColor;
      box-shadow:
        0 -5px 0 currentColor,
        0 5px 0 currentColor;
    }

    /*
     * Below the tablet breakpoint the rail is replaced by the drawer launcher.
     * A permanent rail eats most of a phone screen, and Drawer already handles
     * the focus trap and the scroll lock.
     */
    @media (max-width: 767px) {
      .wrn-sidebar__launcher {
        display: inline-flex;
      }

      .wrn-sidebar__rail {
        display: none;
      }
    }
  }
}
