import * as fileUploadMachine from "@zag-js/file-upload";
import type { MachineInput } from "marko-zag";
import { cn } from "#lib/utils.ts";
import { stripOwnProps } from "#lib/native-attrs.ts";
import { buttonVariants } from "../button/variants.ts";
import { fileUpload as styles } from "./classes.ts";

export interface FileUploadFileInfo {
  name: string;
  size: number;
  type: string;
}

export type Input = MachineInput<"input", fileUploadMachine.Props> & {
  filesChange?: (files: FileUploadFileInfo[]) => void;
};

<zag/api=() => fileUploadMachine from=input
  onFileChange(details: fileUploadMachine.FileChangeDetails) {
    input.onFileChange?.(details);
    input.filesChange?.(
      details.acceptedFiles.map((file) => ({
        name: file.name,
        size: file.size,
        type: file.type,
      })),
    );
  }
/>

<const/nativeAttrs=() =>
  stripOwnProps(
    fileUploadMachine.splitProps(input)[1],
    "class",
    "filesChange",
  )
>

<const/formatSize=(bytes: number) => {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}>

<const/triggerVariant=buttonVariants({ variant: "outline", size: "sm" })/>
<const/deleteVariant=buttonVariants({ variant: "ghost", size: "icon" })/>

<div ...api().getRootProps() data-slot="file-upload" class=cn(styles.root, input.class)>
  // Zag makes the dropzone itself a focusable role="button", but ours
  // contains the "Browse files" trigger — an interactive control nested in
  // another (axe: nested-interactive). The trigger is the keyboard path, so
  // the dropzone drops out of the tab order and stays a plain click/drag
  // target for pointer users.
  // `aria-label="dropzone"` from Zag is inert naming on a role-less div
  // (html-validate aria-label-misuse); the dropzone's real name comes from
  // its trigger content, so it is stripped alongside role/tabIndex.
  <const/dropzoneProps=(() => {
    const { role, tabIndex, tabindex, "aria-label": ariaLabel, ...rest } =
      api().getDropzoneProps() as Record<string, unknown>;
    return rest;
  })()>
  <div
    ...dropzoneProps
    data-slot="file-upload-dropzone"
    class=styles.dropzone
  >
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      class=styles.dropzoneIcon
    >
      <path d="M12 13v8"/>
      <path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242"/>
      <path d="m8 17 4-4 4 4"/>
    </svg>
    <div class=styles.dropzoneText>
      <span class=styles.dropzoneTextEmphasis>Drag and drop files here</span>
    </div>
    <p class=styles.dropzoneHint>or click browse to choose files</p>
    <button type="button" ...api().getTriggerProps() data-slot="file-upload-trigger" class=cn(triggerVariant, styles.trigger)>
      Browse files
    </button>
    <input type="text" ...nativeAttrs() ...api().getHiddenInputProps() data-slot="file-upload-hidden-input"/>
  </div>

  <if=api().acceptedFiles.length>
    <ul ...api().getItemGroupProps() data-slot="file-upload-item-group" class=styles.itemGroup>
      <for|file| of=api().acceptedFiles>
        <li ...api().getItemProps({ file }) data-slot="file-upload-item" class=styles.item>
          <div class=styles.itemInfo>
            <span ...api().getItemNameProps({ file }) data-slot="file-upload-item-name" class=styles.itemName>${file.name}</span>
            <span ...api().getItemSizeTextProps({ file }) data-slot="file-upload-item-size-text" class=styles.itemSizeText>${formatSize(file.size)}</span>
          </div>
          <button type="button"
            ...api().getItemDeleteTriggerProps({ file })
            data-slot="file-upload-item-delete-trigger"
            class=cn(deleteVariant, styles.itemDeleteTrigger)
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="24"
              height="24"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
              class=styles.itemDeleteIcon
            >
              <path d="M18 6 6 18"/>
              <path d="m6 6 12 12"/>
            </svg>
            <span class=styles.itemDeleteSrOnly>Remove ${file.name}</span>
          </button>
        </li>
      </for>
    </ul>
  </if>
</div>

<return=api>
