<script lang="ts">
  // ARIA tablist + tab + tabpanel. 좌우 화살표 키 nav.
  // children snippet은 (activeId: string) => UI 시그니처로 받는다.
  // 사용처:
  //   <Tabs tabs={[{id:'edit',label:'편집'},{id:'preview',label:'미리보기'}]} bind:value={mode}>
  //     {#snippet children(activeId)}
  //       {#if activeId === 'edit'}<EditPanel />{/if}
  //       {#if activeId === 'preview'}<PreviewPanel />{/if}
  //     {/snippet}
  //   </Tabs>
  import type { Snippet } from 'svelte';

  export interface Tab {
    id: string;
    label: string;
    disabled?: boolean;
  }

  interface Props {
    tabs: Tab[];
    value?: string;
    children?: Snippet<[string]>;
    class?: string;
  }

  let { tabs, value = $bindable(tabs[0]?.id ?? ''), children, class: className = '' }: Props = $props();

  const autoId = $props.id();

  function tabId(id: string) {
    return `tab-${autoId}-${id}`;
  }
  function panelId(id: string) {
    return `panel-${autoId}-${id}`;
  }

  function select(id: string) {
    if (tabs.find((t) => t.id === id)?.disabled) return;
    value = id;
  }

  function onKeydown(e: KeyboardEvent) {
    const enabled = tabs.filter((t) => !t.disabled);
    const idx = enabled.findIndex((t) => t.id === value);
    if (idx === -1) return;
    if (e.key === 'ArrowRight') {
      e.preventDefault();
      const next = enabled[(idx + 1) % enabled.length];
      select(next.id);
      document.getElementById(tabId(next.id))?.focus();
    } else if (e.key === 'ArrowLeft') {
      e.preventDefault();
      const prev = enabled[(idx - 1 + enabled.length) % enabled.length];
      select(prev.id);
      document.getElementById(tabId(prev.id))?.focus();
    } else if (e.key === 'Home') {
      e.preventDefault();
      const first = enabled[0];
      select(first.id);
      document.getElementById(tabId(first.id))?.focus();
    } else if (e.key === 'End') {
      e.preventDefault();
      const last = enabled[enabled.length - 1];
      select(last.id);
      document.getElementById(tabId(last.id))?.focus();
    }
  }
</script>

<div class={className}>
  <div
    role="tablist"
    tabindex="-1"
    class="flex items-center gap-1 border-b border-default"
    onkeydown={onKeydown}
  >
    {#each tabs as tab (tab.id)}
      {@const active = tab.id === value}
      <button
        type="button"
        role="tab"
        id={tabId(tab.id)}
        aria-selected={active}
        aria-controls={panelId(tab.id)}
        tabindex={active ? 0 : -1}
        disabled={tab.disabled}
        onclick={() => select(tab.id)}
        class={[
          'px-3 h-9 text-sm font-medium border-b-2 -mb-px transition-colors',
          'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-ring rounded-t',
          active
            ? 'text-accent border-accent'
            : 'text-dim border-transparent hover:text-text',
          tab.disabled ? 'opacity-50 cursor-not-allowed' : '',
        ].join(' ')}
      >
        {tab.label}
      </button>
    {/each}
  </div>

  <div
    role="tabpanel"
    id={panelId(value)}
    aria-labelledby={tabId(value)}
    tabindex="0"
    class="focus-visible:outline-none"
  >
    {@render children?.(value)}
  </div>
</div>
