<script setup lang="ts">
/**
 * AppSidebar — composes SidebarHeader + SidebarNav + WorkspaceSwitcher.
 *
 * Two rendering modes (RFC §4):
 *
 *   DESKTOP (≥ lg / 1024px): a permanent <aside> (hidden lg:flex column).
 *     Width responds to sidebarCollapsed: expanded → w-64 (256px), collapsed → w-16 (64px).
 *     These match crewli-starter's --sidebar-w / --sidebar-w-collapsed CSS variables.
 *
 *   MOBILE (< lg): a PrimeVue <Drawer> bound to shell.mobileOpen via a writable
 *     computed (`mobileVisible`). The Drawer contains the same 3 children as the
 *     <aside> — a small amount of template duplication kept intentional for
 *     readability (no render-fn or dynamic component indirection needed at this scale).
 *
 *     The Drawer is conditionally MOUNTED (v-if="isMobile") rather than hidden via
 *     a CSS class. PrimeVue Drawer teleports its overlay to <body> via an internal
 *     Portal; a `lg:hidden` class on the component node does NOT suppress the
 *     teleported overlay. By unmounting on desktop we guarantee no modal backdrop /
 *     focus-trapped dialog can appear on wide viewports regardless of mobileOpen state.
 *
 * Nav data: as of Plan 2.5 P4, SidebarNav reads APP_NAVIGATION from
 * @/config/navigation directly — no prop is threaded through AppSidebar.
 * The components-v2 import boundary still applies to @/navigation (the v1
 * source), but @/config/navigation is the unclassified central registry
 * and is consumed in-place by SidebarNav.
 *
 * Deliberate simplification: crewli-starter's bespoke Teleport tooltip (shown in
 * collapsed mode for nav items) is NOT ported here. SidebarNav already provides
 * native `:title` tooltips in collapsed mode, which is functionally equivalent
 * for keyboard/mouse users and avoids the bespoke fixed-position Teleport mechanism.
 * Tracked for re-evaluation if custom tooltip styling is required later.
 *
 * CSS translation (main.css → Tailwind):
 *   .sidebar (desktop)   → flex flex-col overflow-hidden bg-[var(--p-surface-card)]
 *                          border-e border-[var(--p-content-border-color)] z-40
 *                          transition-[width] duration-200
 *                          w-64 (expanded) | w-16 (collapsed)
 *   .sidebar (mobile)    → full-height column inside the Drawer
 *   .drawer-open (blur)  → handled by parent layout; not in scope here
 */

import { computed } from 'vue'
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
import Drawer from 'primevue/drawer'
import { useShellUiStore } from '@/stores/useShellUiStore'
import SidebarHeader from '@/components-v2/layout/SidebarHeader.vue'
import SidebarNav from '@/components-v2/layout/SidebarNav.vue'
import WorkspaceSwitcher from '@/components-v2/layout/WorkspaceSwitcher.vue'

const shell = useShellUiStore()

// Shared breakpoint signal — must match SidebarHeader and the CSS `lg:` boundary (1024px).
// useBreakpoints(breakpointsTailwind).smaller('lg') is true below 1024px, equivalent to
// max-width: 1023px. Both components import from the same Tailwind constant so the
// desktop/mobile boundary cannot drift.
const isMobile = useBreakpoints(breakpointsTailwind).smaller('lg')

/**
 * Writable computed so we can use v-model:visible on PrimeVue Drawer
 * without mutating the store ref directly.
 */
const mobileVisible = computed<boolean>({
  get: () => shell.mobileOpen,
  set: (v: boolean) => shell.setMobileOpen(v),
})
</script>

<template>
  <!--
    DESKTOP: permanent <aside>, hidden below lg, flex column above lg.
    Width transitions between w-64 (expanded) and w-16 (collapsed).
    `hidden lg:flex` is effective here because <aside> is not teleported.
  -->
  <!-- desktop -->
  <aside
    class="hidden lg:flex flex-col overflow-hidden bg-[var(--p-surface-card)] border-e border-[var(--p-content-border-color)] z-40 transition-[width] duration-200 flex-shrink-0"
    :class="shell.sidebarCollapsed ? 'w-16' : 'w-64'"
  >
    <SidebarHeader />
    <SidebarNav :collapsed="shell.sidebarCollapsed" />
    <WorkspaceSwitcher :collapsed="shell.sidebarCollapsed" />
  </aside>

  <!--
    MOBILE: PrimeVue Drawer, conditionally MOUNTED only when isMobile is true.
    v-if (not v-show / CSS) is required because PrimeVue Drawer teleports its
    overlay to <body> — a CSS class on the component node does NOT reach the
    teleported portal. Unmounting on desktop ensures the overlay and focus-trap
    are never created on wide viewports, regardless of shell.mobileOpen state.

    The Drawer's own overlay handles backdrop / close-on-outside-click.
    position="left" gives the sidebar-style panel. pt (passthrough) removes
    Drawer's default padding so our children control their own spacing exactly
    as on desktop.

    The children are intentionally repeated (not factored into a slot or
    render-fn) — the 3-component block is short and the duplication is
    preferable to the indirection of a dynamic component or slot wiring.
  -->
  <!-- mobile -->
  <Drawer
    v-if="isMobile"
    v-model:visible="mobileVisible"
    position="left"
    class="!w-64"
    :pt="{
      content: { class: 'flex flex-col p-0 overflow-hidden h-full' },
      header: { class: 'hidden' },
    }"
  >
    <SidebarHeader />
    <SidebarNav :collapsed="false" />
    <WorkspaceSwitcher :collapsed="false" />
  </Drawer>
</template>
