import * as tocMachine from "@zag-js/toc";
import type { MachineInput } from "marko-zag";
import { cn } from "#lib/utils.ts";
import { stripOwnProps } from "#lib/native-attrs.ts";
import { toc as styles } from "./classes.ts";

// Zag's TocItem only carries `value` (heading slug) and `depth`; the display
// text is this component's own concern, so items may carry an optional
// `label` alongside them (falls back to the slug when omitted).
export interface TocItem extends tocMachine.TocItem {
  label?: string;
}

export type Input = MachineInput<"nav", tocMachine.Props> & {
  items: TocItem[];
  activeIdsChange?: (activeIds: string[]) => void;
  activeItemsChange?: (activeItems: TocItem[]) => void;
  title?: string;
};

<zag/api=() => tocMachine from=input
  onActiveChange(details: tocMachine.ActiveChangeDetails) {
    input.onActiveChange?.(details);
    input.activeIdsChange?.(details.activeIds);
    input.activeItemsChange?.(details.activeItems as TocItem[]);
  }
/>

<const/tocItems=() => api().items as TocItem[]>

<const/nativeAttrs=() =>
  stripOwnProps(
    tocMachine.splitProps(input)[1],
    "class",
    "activeIdsChange",
    "activeItemsChange",
    // NOTE: no "items" here — `items` is a TocProps key, so Zag's splitProps
    // has already claimed it and it is absent from the leftover object.
    // Listing it was a compile error (keys must be `keyof Source`).
    "title",
  )
>

<nav
  ...nativeAttrs()
  ...api().getRootProps()
  data-slot="toc-root"
  class=cn(styles.root, input.class)
>
  <if=input.title>
    <p ...api().getTitleProps() data-slot="toc-title" class=styles.title>${input.title}</p>
  </if>
  // aria-hidden: the active-position indicator is decorative. It lives
  // OUTSIDE the <ul> — a bare <span> is not valid content for a list
  // (html-validate element-permitted-content, axe list only-listitems).
  // Absolutely positioned, so DOM order relative to the list is cosmetic.
  <span
    ...api().getIndicatorProps()
    data-slot="toc-indicator"
    aria-hidden="true"
    class=styles.indicator
  />
  <ul ...api().getListProps() data-slot="toc-list" class=styles.list>
    <for|item| of=tocItems()>
      <li
        ...api().getItemProps({ item })
        data-slot="toc-item"
        class=styles.item
      >
        <a
          href=`#${item.value}`
          ...api().getLinkProps({ item })
          data-slot="toc-link"
          class=styles.link
        >
          ${item.label ?? item.value}
        </a>
      </li>
    </for>
  </ul>
</nav>

<return=api>
