<script setup lang="ts">
import { nextTick, ref, watch } from 'vue'
import { RouterLink } from 'vue-router'
import type { NavigationEntry, NavigationSection } from './navigationCatalog'

const props = withDefaults(defineProps<{
  sections: NavigationSection[]
  favorites?: NavigationEntry[]
  activePath?: string
  collapsed?: boolean
  collapsedSections?: readonly string[]
  mobileOpen?: boolean
}>(), { favorites: () => [], activePath: '', collapsed: false })
const emit = defineEmits<{ toggleCollapsed: []; toggleSection: [module: string]; closeMobile: [] }>()
const navigation = ref<HTMLElement | null>(null)

function isEntryActive(path: string): boolean {
  return props.activePath === path || props.activePath.startsWith(`${path}/`)
}

function toggleSection(module: string): void {
  emit('toggleSection', module)
}

function trapFocus(event: KeyboardEvent): void {
  if (!props.mobileOpen || event.key !== 'Tab' || !navigation.value) return
  const focusable = [...navigation.value.querySelectorAll<HTMLElement>('button, a')].filter(element => !element.hasAttribute('disabled'))
  if (!focusable.length) return
  const first = focusable[0]
  const last = focusable.at(-1) ?? first
  if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus() }
  else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus() }
}

watch(() => props.mobileOpen, async open => {
  if (open) { await nextTick(); navigation.value?.querySelector<HTMLElement>('.ks-side-nav__mobile-close')?.focus() }
})
</script>

<template>
  <aside ref="navigation" class="ks-side-nav" :class="{ 'ks-side-nav--collapsed': props.collapsed, 'ks-side-nav--mobile-open': props.mobileOpen }" aria-label="주요 메뉴" @keydown="trapFocus">
    <button type="button" class="ks-side-nav__mobile-close" aria-label="주요 메뉴 닫기" @click="emit('closeMobile')">×</button>
    <button type="button" class="ks-side-nav__toggle" :aria-expanded="!props.collapsed" @click="emit('toggleCollapsed')">
      {{ props.collapsed ? '»' : '« 접기' }}
    </button>
    <template v-if="!props.collapsed">
      <section v-if="favorites.length" class="ks-side-nav__section">
        <h2>즐겨찾기</h2>
        <RouterLink v-for="entry in favorites" :key="entry.screenId" :to="entry.path" :class="{ active: isEntryActive(entry.path) }" :aria-current="isEntryActive(entry.path) ? 'page' : undefined">★ {{ entry.title }}</RouterLink>
      </section>
      <section v-for="section in sections" :key="section.module" class="ks-side-nav__section">
        <button type="button" class="ks-side-nav__section-toggle" :aria-expanded="!props.collapsedSections?.includes(section.module)" @click="toggleSection(section.module)">{{ section.module }}</button>
        <template v-if="!props.collapsedSections?.includes(section.module)">
          <RouterLink v-for="entry in section.entries" :key="entry.screenId" :to="entry.path" :class="{ active: isEntryActive(entry.path) }" :aria-current="isEntryActive(entry.path) ? 'page' : undefined">{{ entry.title }}</RouterLink>
        </template>
      </section>
    </template>
  </aside>
</template>

<style scoped>
.ks-side-nav { width: var(--ks-shell-sidenav-width); flex-shrink: 0; display: grid; gap: var(--ks-space-3); align-content: start; padding: var(--ks-space-3) var(--ks-space-2); border-right: 1px solid var(--ks-color-border); background: var(--ks-color-surface); overflow-y: auto; }
.ks-side-nav--collapsed { width: var(--ks-shell-sidenav-collapsed); padding: var(--ks-space-3) var(--ks-space-1); }
.ks-side-nav__toggle { justify-self: end; border: 0; background: transparent; color: var(--ks-color-text-muted); font-size: var(--ks-font-caption); cursor: pointer; }
.ks-side-nav__section { display: grid; gap: var(--ks-space-1); }
.ks-side-nav__section h2 { margin: 0 var(--ks-space-2); font-size: var(--ks-font-caption); font-weight: 600; color: var(--ks-color-text-muted); text-transform: uppercase; }
.ks-side-nav__section-toggle { border: 0; background: transparent; text-align: left; margin: 0 var(--ks-space-2); padding: 0; color: var(--ks-color-text-muted); font-size: var(--ks-font-caption); font-weight: 600; text-transform: uppercase; cursor: pointer; }
.ks-side-nav__section a { padding: var(--ks-space-2) var(--ks-space-2); border-radius: var(--ks-radius-sm); text-decoration: none; color: var(--ks-color-text); font-size: var(--ks-font-body); }
.ks-side-nav__section a.active, .ks-side-nav__section a.router-link-active { background: var(--ks-color-neutral-100); font-weight: 700; }
.ks-side-nav__mobile-close { display: none; }
@media (max-width: 900px) {
  .ks-side-nav { position: fixed; inset: 0 auto 0 0; z-index: 50; width: min(20rem, 88vw); transform: translateX(-105%); transition: transform .18s ease; box-shadow: var(--ks-shadow-lg); }
  .ks-side-nav--mobile-open { transform: translateX(0); }
  .ks-side-nav__mobile-close { display: block; justify-self: end; border: 0; background: transparent; font-size: 1.5rem; cursor: pointer; }
}
</style>
