import * as toggleGroupMachine from "@zag-js/toggle-group";
import { mergeProps, type MachineInput } from "marko-zag";
import { toggleVariants, type ToggleVariants } from "../toggle/variants.ts";
import { cn } from "#lib/utils.ts";
import { stripOwnProps } from "#lib/native-attrs.ts";
import { toggleGroup as styles } from "./classes.ts";

export interface ToggleGroupItem {
  value: string;
  label: string;
  disabled?: boolean;
}

export interface ToggleGroupItemAttrs {
  value: string;
  disabled?: boolean;
  content?: Marko.Body;
}

// Dual API: compound attr tags (`<@item>`) are the primary, Marko-idiomatic
// form; `items=` remains as sugar for the data-driven case. If both are
// supplied, attr tags win (see agent/reports/compound-tag-dx.md).
//
// `spacing`/`orientation` mirror upstream's ToggleGroupContext defaults
// (spacing=2, orientation="horizontal"); zag's own `orientation` prop drives
// keyboard nav, so it is read back out of the resolved machine props rather
// than duplicated.
export type Input = MachineInput<"div", toggleGroupMachine.Props> &
  ToggleVariants & {
    items?: ToggleGroupItem[];
    item?: Marko.AttrTag<ToggleGroupItemAttrs>;
    spacing?: number;
    valueChange?: (value: string[]) => void;
  };

// Normalize BOTH sources into ONE explicit common shape (mirrors
// radio-group.marko) so the render path below never branches on the source
// and needs no casts: `content` carries the attr-tag markup body, `label`
// the items= string fallback. Attr tags win if both are present.
<const/itemTags=[...(input.item ?? [])].map((item) => ({ value: item.value, disabled: item.disabled, label: undefined as string | undefined, content: item.content }))/>
<const/items=(itemTags.length > 0 ? itemTags : (input.items ?? []).map((item) => ({ value: item.value, disabled: item.disabled, label: item.label as string | undefined, content: undefined as Marko.Body | undefined })))/>

<zag/api=() => toggleGroupMachine from=input/>

<const/nativeAttrs=() =>
  stripOwnProps(
    toggleGroupMachine.splitProps(input)[1],
    "class",
    "items",
    "item",
    "variant",
    "size",
    "spacing",
    "valueChange",
  )
>

<const/spacing=input.spacing ?? 2/>

<div
  ...nativeAttrs()
  ...mergeProps(api().getRootProps(), { style: { "--gap": spacing } })
  data-slot="toggle-group"
  data-variant=(input.variant ?? "default")
  data-size=(input.size ?? "default")
  data-spacing=spacing
  class=cn(styles.root, input.class)
>
  <for|item| of=items by=(item) => item.value>
    <button type="button"
      ...api().getItemProps({ value: item.value, disabled: item.disabled })
      data-slot="toggle-group-item"
      data-variant=(input.variant ?? "default")
      data-size=(input.size ?? "default")
      data-spacing=spacing
      class=cn(styles.item, toggleVariants({ variant: input.variant, size: input.size }))
    >
      <if=item.content>
        <${item.content}/>
      </if>
      <else>
        ${item.label}
      </else>
    </button>
  </for>
</div>

<return=api>
