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

// MachineInput = native <div> attributes ∩ the machine's full Props, with
// `id` made optional (generated below, overridable). `openChange` is
// additive sugar enabling Marko's two-way bind shorthand
// (<Tooltip open:=myState/>); Zag's own `onOpenChange` also works and
// receives the details object.
export type Input = MachineInput<"span", tooltipMachine.Props> & {
  /** Trigger render-prop — typically the element the tooltip describes. */
  trigger: Marko.AttrTag<{ content: Marko.Body<[Record<string, unknown>]> }>;
  /** Tooltip content shown when open. */
  content: string | Marko.Body;
  openChange?: (open: boolean) => void;
};

// <zag> wires the machine in one tag and returns `api` as a GETTER —
// call it at every use site. Getters are the serializable currency of
// Marko's resumability: the api object itself must never become reactive
// state. See /docs/creating-components.
<zag/api=() => tooltipMachine from=input/>

// Whatever is neither machine-owned (splitProps) nor component-owned
// (class, openChange, trigger, content) passes through to the root span:
// aria-*, data-*, arbitrary attributes callers attach to the tooltip as
// a whole.
<const/nativeAttrs=() =>
  stripOwnProps(tooltipMachine.splitProps(input)[1], "class", "openChange", "trigger", "content")
>

<span ...nativeAttrs() data-slot="tooltip">
  <${input.trigger.content}({ ...api().getTriggerProps(), "data-slot": "tooltip-trigger" })/>
</span>
// The portal lives OUTSIDE the span root: <zag-portal> renders a real
// element, and a <div> is not valid phrasing content inside <span>
// (html-validate element-permitted-content). The portal's contents are
// absolutely positioned regardless of DOM parent.
<zag-portal>
  <if=api().open>
    <div ...api().getPositionerProps() style=positionerStyle data-slot="tooltip-positioner">
      <div
        ...api().getContentProps()
        data-slot="tooltip-content"
        class=cn(styles.content, input.class)
      >
        <if=(typeof input.content === "string")>
          ${input.content}
        </if>
        <else>
          <${input.content}/>
        </else>
        <div ...api().getArrowProps() data-slot="tooltip-arrow">
          <div ...api().getArrowTipProps() data-slot="tooltip-arrow-tip" class=styles.arrowTip/>
        </div>
      </div>
    </div>
  </if>
</zag-portal>

// Parents can receive the api getter: <Tooltip/tooltipApi/> then
// `tooltipApi().open` — it stays live across machine updates.
<return=api>
