---
import { SITE, CATEGORIES, INSIGHT_TOPICS, type InsightTopicSlug } from '../consts';
import { getCollection } from 'astro:content';
import HeaderNavGroup from './HeaderNavGroup.astro';
import ThemePicker from './ThemePicker.astro';

const { pathname } = Astro.url;
const insightArticles = await getCollection('insights');
const activeInsightTopics = INSIGHT_TOPICS.filter((topic) =>
  insightArticles.some((article) => article.data.topic === topic.slug),
);
const categoryLabel = (slug: string) => CATEGORIES.find((category) => category.slug === slug)?.label ?? slug;
const mapActive = pathname === '/knowledge-map/';
const newsActive = pathname === '/category/news/';
const groups: {
  id: string;
  label: string;
  active: boolean;
  items: { href: string; label: string; description: string; topic?: InsightTopicSlug; mobileLabelClass?: string }[];
}[] = [
  {
    id: 'guides',
    label: '실전 가이드',
    active: pathname.startsWith('/posts/') || pathname.startsWith('/work-kit/') || pathname.startsWith('/ebooks/') || (pathname.startsWith('/category/') && !newsActive),
    items: [
      { href: '/posts/', label: '전체 실전 자료', description: '가이드와 업무 템플릿을 한곳에서 탐색' },
      { href: '/category/usage/', label: categoryLabel('usage'), description: '주요 AI 도구의 시작과 활용' },
      { href: '/category/work/', label: categoryLabel('work'), description: '보고서·엑셀·이메일 등 업무에 적용' },
      { href: '/category/prompts/', label: categoryLabel('prompts'), description: '복사해서 쓰는 질문과 작성 요령' },
      { href: '/work-kit/', label: '업무 도구함', description: '독자 작성한 업무 지침·프롬프트·검수표' },
      { href: '/ebooks/', label: '무료 전자책', description: 'AI 실전 전자책 5권의 소개·목차·무료 PDF' },
      { href: '/category/troubleshooting/', label: categoryLabel('troubleshooting'), description: '로그인·한도·결제 문제 해결' },
      { href: '/category/comparison/', label: categoryLabel('comparison'), description: '목적과 비용에 맞는 도구 선택' },
      { href: '/posts/senior-ai-guide/', label: '시니어 입문', description: '처음 접하는 분을 위한 차근차근 시작법' },
    ],
  },
  {
    id: 'lab',
    label: '실전 제작 LAB',
    active: ['/projects/', '/skills/', '/games/', '/game-sources/', '/music/', '/video-lab/', '/recipes/', '/file-tools/', '/decision-lab/'].some((path) => pathname.startsWith(path)),
    items: [
      { href: '/video-lab/', label: '영상 제작 랩', description: '음악 포함 제품 필름 6편과 장면별 제작 해설' },
      { href: '/projects/', label: '프로젝트 랩', description: '직접 만든 앱과 도구의 제작기', mobileLabelClass: 'mobile-project-nav-label' },
      { href: '/skills/', label: 'AI 스킬 랩', description: '반복 작업을 자동화한 방법과 경험', mobileLabelClass: 'mobile-skill-nav-label' },
      { href: '/games/', label: 'AI 게임 프로젝트', description: '직접 만든 게임과 개선 과정' },
      { href: '/game-sources/', label: '웹게임 소스', description: '고전풍 게임의 코드 해설과 소스 다운로드' },
      { href: '/music/', label: 'AI 음악 랩', description: '영어 가사로 만든 AI 음악과 제작 이야기' },
      { href: '/decision-lab/', label: 'AI 판단 실습실', description: '예제로 문의 분류·자동 처리 기준·사람 검토 체험' },
      { href: '/file-tools/', label: '파일 도구', description: '브라우저에서 이미지와 PDF를 처리하는 도구 모음' },
      { href: '/recipes/', label: 'AI 제작 레시피', description: '원하는 결과물을 만드는 단계별 가이드', mobileLabelClass: 'mobile-recipe-nav-label' },
    ],
  },
  {
    id: 'insights',
    label: '전문 인사이트',
    active: pathname.startsWith('/insights/') || pathname.startsWith('/editor/'),
    items: [
      { href: '/insights/', label: '전체 인사이트', description: 'AI 설계와 운영의 심화 주제 탐색' },
      ...activeInsightTopics.map((topic) => ({ href: `/insights/?topic=${topic.slug}`, label: topic.label, description: topic.description, topic: topic.slug })),
      { href: '/editor/', label: '글쓰기 관리실', description: '운영자 전용 Markdown 편집·검수' },
    ],
  },
];
---

<header class="site-header" data-site-header>
  <div class="container wide header-inner">
    <a href="/" class="brand">
      <span class="brand-mark" aria-hidden="true">AI</span>
      <span class="brand-text">{SITE.title}</span>
    </a>
    <div class="header-right">
      <nav class="desktop-nav" aria-label="주요 메뉴">
        {groups.map((group) => <HeaderNavGroup group={group} variant="desktop" />)}
        <a href="/knowledge-map/" class:list={['nav-news', { active: mapActive }]} aria-current={mapActive ? 'page' : undefined}>AI 지식 지도</a>
      </nav>
      <button type="button" class="header-search-btn" data-open-search aria-label="검색창 열기">
        <span class="search-btn-icon" aria-hidden="true">🔍</span>
        <span class="search-btn-text">가이드·프롬프트 검색</span>
        <kbd class="search-btn-kbd" aria-hidden="true">⌘K</kbd>
      </button>
      <ThemePicker variant="desktop" />
      <details class="mobile-menu" data-mobile-menu>
        <summary class="mobile-menu-toggle" aria-controls="header-mobile-panel">
          <span class="menu-icon menu-icon-open" aria-hidden="true">☰</span>
          <span class="menu-icon menu-icon-close" aria-hidden="true">×</span>
          <span class="menu-label menu-label-open">전체 메뉴 열기</span>
          <span class="menu-label menu-label-close">전체 메뉴 닫기</span>
        </summary>
        <nav id="header-mobile-panel" class="mobile-menu-panel" aria-label="모바일 전체 메뉴">
          {groups.map((group) => <HeaderNavGroup group={group} variant="mobile" />)}
          <a href="/knowledge-map/" class:list={['mobile-news', { active: mapActive }]} aria-current={mapActive ? 'page' : undefined}>AI 지식 지도</a>
          <ThemePicker variant="mobile" />
        </nav>
      </details>
    </div>
  </div>
</header>
<noscript><style is:inline>
  .site-header:has([data-mobile-menu][open]) { position: relative; }
  .site-header:has([data-mobile-menu][open]) .header-right { flex-wrap: wrap; }
  .site-header [data-mobile-menu][open] { width: 100%; }
  .site-header [data-mobile-menu][open] .mobile-menu-panel { position: static; max-height: none; margin-top: 0.5rem; }
</style></noscript>

<style>
  .site-header {
    container: site-header / inline-size;
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--bg-card);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
  }

  .header-inner,
  .header-right {
    display: flex;
    align-items: center;
    gap: 1rem;
  }

  .header-inner {
    position: relative;
    justify-content: space-between;
    flex-wrap: wrap;
    padding-block: 0.65rem;
  }

  .brand {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 1;
    min-width: 0;
    max-width: 100%;
    color: var(--text);
    font-size: 1.05rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    white-space: normal;
    text-decoration: none;
  }

  .brand-mark {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 8px;
    background: var(--cta);
    color: var(--cta-text);
    font-size: 0.78rem;
  }

  .header-right {
    min-width: 0;
    max-width: 100%;
    flex-shrink: 0;
    margin-left: auto;
    gap: 0.75rem;
  }

  .desktop-nav {
    display: none;
    align-items: center;
    gap: 1rem;
  }

  .nav-news {
    padding: 0.65rem 0.4rem;
    color: var(--text);
    font-size: 0.92rem;
    font-weight: 700;
    white-space: nowrap;
    text-decoration: none;
  }

  .nav-news:hover,
  .nav-news.active,
  .mobile-news.active {
    color: var(--brand-accent-text);
  }

  .header-search-btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.42rem 0.65rem;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--muted);
    font-size: 0.82rem;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
  }

  .header-search-btn:hover {
    background: var(--bg-card);
    border-color: var(--muted);
  }

  .search-btn-text,
  .search-btn-kbd {
    display: none;
  }

  .search-btn-kbd {
    padding: 0.08rem 0.3rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--bg-card);
    font-family: var(--font-mono);
    font-size: 0.65rem;
  }

  .header-cta {
    display: none;
    padding: 0.45rem 1rem;
    font-size: 0.85rem;
    white-space: nowrap;
    flex-shrink: 0;
  }

  .mobile-menu {
    position: static;
  }

  .mobile-menu-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.35rem;
    height: 2.35rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg-card);
    color: var(--text);
    cursor: pointer;
    list-style: none;
  }

  .mobile-menu-toggle::-webkit-details-marker {
    display: none;
  }

  .menu-icon {
    font-size: 1.25rem;
    line-height: 1;
  }

  .menu-icon-close,
  .menu-label-close {
    display: none;
  }

  .mobile-menu[open] .menu-icon-open,
  .mobile-menu[open] .menu-label-open {
    display: none;
  }

  .mobile-menu[open] .menu-icon-close {
    display: inline;
  }

  .menu-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .mobile-menu[open] .menu-label-close {
    display: block;
  }

  .mobile-menu-panel {
    position: absolute;
    top: calc(100% + 0.5rem);
    left: 1.25rem;
    right: 1.25rem;
    max-height: calc(100dvh - var(--site-header-height, 5rem) - 1rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 0.5rem 1rem 1rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: var(--shadow-md);
  }

  .mobile-news {
    display: block;
    padding: 0.9rem 0.4rem;
    color: var(--text);
    font-size: 1rem;
    font-weight: 700;
  }

  .mobile-cta {
    display: flex;
    margin-top: 0.5rem;
  }

  .brand:focus-visible,
  .nav-news:focus-visible,
  .header-search-btn:focus-visible,
  .header-cta:focus-visible,
  .mobile-menu-toggle:focus-visible,
  .mobile-news:focus-visible,
  .mobile-cta:focus-visible {
    outline: 2px solid var(--brand-accent-text);
    outline-offset: 3px;
    border-radius: 6px;
  }

  @media (min-width: 1024px) {
    .desktop-nav,
    .header-cta {
      display: flex;
    }

    .mobile-menu {
      display: none;
    }
  }

  @media (min-width: 1380px) {
    .search-btn-text,
    .search-btn-kbd {
      display: inline;
    }
  }

  /* Container em units follow enlarged text; viewport breakpoints alone do not.
     Keep the normal 1024/1380px layout, but collapse it when text no longer fits. */
  @container site-header (width < 60em) {
    .desktop-nav,
    .header-cta { display: none; }
    .mobile-menu { display: block; }
  }

  @container site-header (width < 84em) {
    .search-btn-text,
    .search-btn-kbd { display: none; }
  }

  @container site-header (width < 16em) {
    .mobile-menu-panel { left: 0.5rem; right: 0.5rem; padding-inline: 0.5rem; }
  }
</style>

<script>
  const header = document.querySelector<HTMLElement>('[data-site-header]');
  const desktopNav = header?.querySelector<HTMLElement>('.desktop-nav');
  const mobileMenu = header?.querySelector<HTMLDetailsElement>('[data-mobile-menu]');
  const desktopGroups = Array.from(header?.querySelectorAll<HTMLDetailsElement>('.desktop-nav [data-nav-group]') ?? []);
  const mobileGroups = Array.from(header?.querySelectorAll<HTMLDetailsElement>('.mobile-menu [data-nav-group]') ?? []);
  const groups = [...desktopGroups, ...mobileGroups];
  const closeGroups = (targets: HTMLDetailsElement[]) => targets.forEach((group) => { group.open = false; });
  const desktopTheme = header?.querySelector<HTMLElement>('.theme-picker-desktop');
  const mobileTheme = header?.querySelector<HTMLElement>('.theme-picker-mobile');
  const mobileToggle = mobileMenu?.querySelector<HTMLElement>('summary');
  // Chromium can blur a control hidden by CSS before resize/observer callbacks.
  // Remember only header focus; a deliberate blur or pointer action discards it.
  let lastHeaderFocus: HTMLElement | null = null;
  document.addEventListener('focusin', (event) => {
    lastHeaderFocus = event.target instanceof HTMLElement && header?.contains(event.target)
      ? event.target : null;
  });
  document.addEventListener('focusout', () => {
    if (lastHeaderFocus?.getClientRects().length) lastHeaderFocus = null;
  });
  document.addEventListener('pointerdown', () => { lastHeaderFocus = null; });
  let desktopVisible: boolean | undefined;
  const syncHeaderLayout = () => {
    if (!header || !desktopNav) return;
    // A wrapped, enlarged header must not cover hash targets or the last menu item.
    document.documentElement.style.setProperty('--site-header-height', `${header.getBoundingClientRect().height}px`);
    const nextDesktop = getComputedStyle(desktopNav).display !== 'none';
    if (desktopVisible !== undefined && desktopVisible !== nextDesktop) {
      const active = document.activeElement === document.body && lastHeaderFocus
        && !lastHeaderFocus.getClientRects().length ? lastHeaderFocus : document.activeElement;
      const moveToMobile = !nextDesktop && (desktopNav.contains(active) || desktopTheme?.contains(active));
      const moveToDesktop = nextDesktop && mobileMenu?.contains(active);
      const desktopTarget = mobileTheme?.contains(active)
        ? desktopTheme?.querySelector<HTMLElement>('select')
        : desktopGroups[0]?.querySelector<HTMLElement>('summary');
      closeGroups(groups);
      if (mobileMenu) mobileMenu.open = false;
      if (moveToMobile) mobileToggle?.focus();
      if (moveToDesktop) desktopTarget?.focus();
    }
    desktopVisible = nextDesktop;
  };
  syncHeaderLayout();
  if (header && typeof ResizeObserver !== 'undefined') new ResizeObserver(syncHeaderLayout).observe(header);
  window.addEventListener('resize', syncHeaderLayout);

  // Static pages share one HTML file across topic query strings.
  if (window.location.pathname === '/insights/') {
    const topic = new URLSearchParams(window.location.search).get('topic') ?? '';
    header?.querySelectorAll<HTMLAnchorElement>('.nav-sub-link').forEach((link) => {
      const target = new URL(link.href);
      if (target.pathname !== '/insights/') return;
      const current = (target.searchParams.get('topic') ?? '') === topic;
      link.classList.toggle('active', current);
      if (current) link.setAttribute('aria-current', 'page');
      else link.removeAttribute('aria-current');
    });
  }

  for (const peers of [desktopGroups, mobileGroups]) {
    for (const group of peers) {
      group.addEventListener('toggle', () => {
        if (group.open) closeGroups(peers.filter((peer) => peer !== group));
      });
    }
  }

  mobileMenu?.addEventListener('toggle', () => {
    if (!mobileMenu.open) closeGroups(mobileGroups);
  });

  document.addEventListener('click', (event) => {
    if (!(event.target instanceof Node)) return;
    if (!desktopNav?.contains(event.target)) closeGroups(desktopGroups);
    if (mobileMenu?.open && !mobileMenu.contains(event.target)) mobileMenu.open = false;
  });

  desktopNav?.addEventListener('focusout', (event) => {
    if (!(event.relatedTarget instanceof Node) || !desktopNav.contains(event.relatedTarget)) closeGroups(desktopGroups);
  });

  document.addEventListener('keydown', (event) => {
    if (event.key !== 'Escape') return;
    const openGroup = groups.find((group) => group.open && group.contains(document.activeElement))
      ?? groups.find((group) => group.open);
    if (openGroup) {
      event.preventDefault();
      openGroup.open = false;
      openGroup.querySelector<HTMLElement>('summary')?.focus();
    } else if (mobileMenu?.open) {
      event.preventDefault();
      mobileMenu.open = false;
      mobileMenu.querySelector<HTMLElement>('summary')?.focus();
    }
  });

  mobileMenu?.addEventListener('click', (event) => {
    if (event.target instanceof Element && event.target.closest('a[href]')) mobileMenu.open = false;
  });

  // Use the same transition handler: closing first can discard the focused control.
  window.matchMedia('(min-width: 1024px)').addEventListener('change', syncHeaderLayout);
</script>
