"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { DataTable } from "@open-mercato/ui/backend/DataTable";
import { RowActions } from "@open-mercato/ui/backend/RowActions";
import { Button } from "@open-mercato/ui/primitives/button";
import { Badge } from "@open-mercato/ui/primitives/badge";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
import { TagsInput } from "@open-mercato/ui/backend/inputs/TagsInput";
import { Spinner } from "@open-mercato/ui/primitives/spinner";
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { hasFeature } from "@open-mercato/shared/security/features";
import { z } from "zod";
import { E } from "../../../generated/entities.ids.generated.js";
import { Download, Plus, Upload, Trash2, File, FileText, FileSpreadsheet, FileArchive, FileAudio, FileVideo, FileCode } from "lucide-react";
import { buildAttachmentFileUrl } from "@open-mercato/core/modules/attachments/lib/imageUrls";
import { cn } from "@open-mercato/shared/lib/utils";
import { AttachmentDeleteDialog, AttachmentMetadataDialog } from "@open-mercato/ui/backend/detail";
const PAGE_SIZE = 25;
const ENV_APP_URL = (process.env.NEXT_PUBLIC_APP_URL || "").replace(/\/$/, "");
const LIBRARY_ENTITY_ID = "attachments:library";
function filterLibraryAssignments(assignments) {
  return (assignments ?? []).filter((assignment) => assignment.type !== LIBRARY_ENTITY_ID);
}
function formatFileSize(value) {
  if (!Number.isFinite(value)) return "\u2014";
  if (value <= 0) return "0 B";
  const units = ["B", "KB", "MB", "GB", "TB"];
  let idx = 0;
  let current = value;
  while (current >= 1024 && idx < units.length - 1) {
    current /= 1024;
    idx += 1;
  }
  return `${current.toFixed(idx === 0 ? 0 : 1)} ${units[idx]}`;
}
function humanDate(value, locale) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleString(locale ?? void 0);
}
function buildFilterSignature(values) {
  return JSON.stringify(values, Object.keys(values).sort((a, b) => a.localeCompare(b)));
}
function resolveAbsoluteUrl(path) {
  if (!path) return path;
  if (/^https?:\/\//i.test(path)) return path;
  const base = ENV_APP_URL || (typeof window !== "undefined" && window.location?.origin ? window.location.origin : "");
  if (!base) return path;
  const normalizedBase = base.replace(/\/$/, "");
  return `${normalizedBase}${path.startsWith("/") ? path : `/${path}`}`;
}
function resolveFileExtension(fileName) {
  if (!fileName) return "";
  const normalized = fileName.trim();
  if (!normalized) return "";
  const lastDot = normalized.lastIndexOf(".");
  if (lastDot === -1 || lastDot === normalized.length - 1) return "";
  return normalized.slice(lastDot + 1).toLowerCase();
}
const EXTENSION_ICON_MAP = {
  pdf: FileText,
  doc: FileText,
  docx: FileText,
  txt: FileText,
  md: FileText,
  rtf: FileText,
  xls: FileSpreadsheet,
  xlsx: FileSpreadsheet,
  csv: FileSpreadsheet,
  ods: FileSpreadsheet,
  ppt: FileText,
  pptx: FileText,
  zip: FileArchive,
  gz: FileArchive,
  rar: FileArchive,
  tgz: FileArchive,
  "7z": FileArchive,
  tar: FileArchive,
  json: FileCode,
  js: FileCode,
  ts: FileCode,
  jsx: FileCode,
  tsx: FileCode,
  html: FileCode,
  css: FileCode,
  xml: FileCode,
  yaml: FileCode,
  yml: FileCode,
  mp3: FileAudio,
  wav: FileAudio,
  flac: FileAudio,
  ogg: FileAudio,
  mp4: FileVideo,
  mov: FileVideo,
  avi: FileVideo,
  webm: FileVideo
};
const MIME_FALLBACK_ICONS = {
  audio: FileAudio,
  video: FileVideo,
  text: FileText,
  application: FileText
};
function resolveAttachmentPlaceholder(mimeType, fileName) {
  const extension = resolveFileExtension(fileName);
  const normalizedMime = typeof mimeType === "string" ? mimeType.toLowerCase() : "";
  if (extension && EXTENSION_ICON_MAP[extension]) {
    return { icon: EXTENSION_ICON_MAP[extension], label: extension.toUpperCase() };
  }
  if (!extension && normalizedMime.includes("pdf")) {
    return { icon: FileText, label: "PDF" };
  }
  if (!extension && normalizedMime.includes("zip")) {
    return { icon: FileArchive, label: "ZIP" };
  }
  if (!extension && normalizedMime.includes("json")) {
    return { icon: FileCode, label: "JSON" };
  }
  const mimeRoot = normalizedMime.split("/")[0] || "";
  if (mimeRoot && MIME_FALLBACK_ICONS[mimeRoot]) {
    return { icon: MIME_FALLBACK_ICONS[mimeRoot], label: mimeRoot.toUpperCase() };
  }
  const fallbackSource = extension || mimeRoot || "file";
  const fallbackLabel = fallbackSource.slice(0, 6).toUpperCase();
  return { icon: File, label: fallbackLabel };
}
function normalizeCustomFieldSubmitValue(value) {
  if (Array.isArray(value)) {
    return value.filter((entry) => entry !== void 0);
  }
  if (value === void 0) return null;
  return value;
}
function AttachmentAssignmentsEditor({ value, onChange, labels, disabled }) {
  const handleChange = React.useCallback(
    (index, patch) => {
      onChange(value.map((entry, idx) => idx === index ? { ...entry, ...patch } : entry));
    },
    [onChange, value]
  );
  const handleRemove = React.useCallback(
    (index) => {
      onChange(value.filter((_, idx) => idx !== index));
    },
    [onChange, value]
  );
  const handleAdd = React.useCallback(() => {
    onChange([...value, { type: "", id: "", href: "", label: "" }]);
  }, [onChange, value]);
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
    /* @__PURE__ */ jsxs("div", { children: [
      /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: labels.title }),
      /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: labels.description })
    ] }),
    /* @__PURE__ */ jsx("div", { className: "space-y-3", children: value.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "No assignments yet." }) : value.map((entry, index) => /* @__PURE__ */ jsxs("div", { className: "rounded border p-3 space-y-2", children: [
      /* @__PURE__ */ jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [
        /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
          /* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: labels.type }),
          /* @__PURE__ */ jsx(
            "input",
            {
              className: "w-full rounded border px-2 py-1 text-sm",
              value: entry.type,
              disabled,
              onChange: (event) => handleChange(index, { type: event.target.value })
            }
          )
        ] }),
        /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
          /* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: labels.id }),
          /* @__PURE__ */ jsx(
            "input",
            {
              className: "w-full rounded border px-2 py-1 text-sm",
              value: entry.id,
              disabled,
              onChange: (event) => handleChange(index, { id: event.target.value })
            }
          )
        ] })
      ] }),
      /* @__PURE__ */ jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [
        /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
          /* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: labels.href }),
          /* @__PURE__ */ jsx(
            "input",
            {
              className: "w-full rounded border px-2 py-1 text-sm",
              value: entry.href ?? "",
              disabled,
              onChange: (event) => handleChange(index, { href: event.target.value })
            }
          )
        ] }),
        labels.label ? /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
          /* @__PURE__ */ jsx("label", { className: "text-xs font-medium", children: labels.label }),
          /* @__PURE__ */ jsx(
            "input",
            {
              className: "w-full rounded border px-2 py-1 text-sm",
              value: entry.label ?? "",
              disabled,
              onChange: (event) => handleChange(index, { label: event.target.value })
            }
          )
        ] }) : null
      ] }),
      /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
        Button,
        {
          type: "button",
          size: "sm",
          variant: "outline",
          disabled,
          onClick: () => handleRemove(index),
          className: "inline-flex items-center gap-1 text-muted-foreground",
          children: [
            /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" }),
            labels.remove
          ]
        }
      ) })
    ] }, `${index}-${entry.type}-${entry.id}`)) }),
    /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled, onClick: handleAdd, className: "inline-flex items-center gap-1", children: [
      /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
      labels.add
    ] })
  ] });
}
function AttachmentFilesField({
  value,
  setValue,
  disabled,
  labels,
  uploading
}) {
  const files = React.useMemo(() => Array.isArray(value) ? value : [], [value]);
  const [isDragOver, setDragOver] = React.useState(false);
  const fileInputRef = React.useRef(null);
  const acceptFiles = React.useCallback(
    (list) => {
      if (!list?.length) return;
      const dedupe = new Map(files.map((file) => [`${file.name}:${file.size}`, file]));
      Array.from(list).forEach((file) => {
        dedupe.set(`${file.name}:${file.size}`, file);
      });
      setValue(Array.from(dedupe.values()));
    },
    [files, setValue]
  );
  const handleDrop = React.useCallback(
    (event) => {
      if (disabled || uploading) return;
      event.preventDefault();
      event.stopPropagation();
      setDragOver(false);
      acceptFiles(event.dataTransfer?.files ?? null);
    },
    [acceptFiles, disabled, uploading]
  );
  const handleDragOver = React.useCallback(
    (event) => {
      if (disabled || uploading) return;
      event.preventDefault();
      event.stopPropagation();
      setDragOver(true);
    },
    [disabled, uploading]
  );
  const handleDragLeave = React.useCallback((event) => {
    event.preventDefault();
    event.stopPropagation();
    setDragOver(false);
  }, []);
  const removeFile = React.useCallback(
    (name, size) => {
      if (disabled || uploading) return;
      setValue(files.filter((file) => !(file.name === name && file.size === size)));
    },
    [disabled, files, setValue, uploading]
  );
  const pickFiles = React.useCallback(() => {
    if (disabled || uploading) return;
    fileInputRef.current?.click();
  }, [disabled, uploading]);
  const renderFileList = () => {
    if (!files.length) {
      return /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: labels.empty });
    }
    return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: files.map((candidate) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded border px-3 py-2 text-sm", children: [
      /* @__PURE__ */ jsxs("div", { children: [
        /* @__PURE__ */ jsx("div", { className: "font-medium", children: candidate.name }),
        /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: formatFileSize(candidate.size) })
      ] }),
      /* @__PURE__ */ jsx(
        Button,
        {
          type: "button",
          variant: "ghost",
          size: "icon",
          onClick: () => removeFile(candidate.name, candidate.size),
          disabled: disabled || uploading,
          children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
        }
      )
    ] }, `${candidate.name}-${candidate.size}`)) });
  };
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
    /* @__PURE__ */ jsxs(
      "div",
      {
        className: cn(
          "flex flex-col items-center justify-center rounded-lg border border-dashed p-6 text-center transition-colors",
          isDragOver ? "border-primary bg-primary/5" : "border-muted-foreground/30",
          disabled || uploading ? "opacity-70" : ""
        ),
        onDrop: handleDrop,
        onDragOver: handleDragOver,
        onDragLeave: handleDragLeave,
        role: "presentation",
        children: [
          /* @__PURE__ */ jsx(Upload, { className: "mx-auto h-6 w-6 text-muted-foreground" }),
          /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: labels.dropHint }),
          /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", className: "mt-4", onClick: pickFiles, disabled: disabled || uploading, children: uploading ? labels.uploading : labels.choose }),
          /* @__PURE__ */ jsx(
            "input",
            {
              ref: fileInputRef,
              type: "file",
              className: "hidden",
              multiple: true,
              onChange: (event) => {
                acceptFiles(event.target.files);
                event.currentTarget.value = "";
              },
              disabled: disabled || uploading
            }
          )
        ]
      }
    ),
    renderFileList()
  ] });
}
function AttachmentUploadForm({ partitions, availableTags, onUploaded, onCancel }) {
  const t = useT();
  const [isUploading, setIsUploading] = React.useState(false);
  const [uploadProgress, setUploadProgress] = React.useState({ completed: 0, total: 0 });
  const partitionOptions = React.useMemo(
    () => partitions.map((entry) => ({
      value: entry.code,
      label: entry.title || entry.code
    })),
    [partitions]
  );
  const assignmentLabels = React.useMemo(
    () => ({
      title: t("attachments.library.upload.assignments.title", "Assignments"),
      description: t(
        "attachments.library.upload.assignments.description",
        "Optionally link this file to existing records now or add them later."
      ),
      type: t("attachments.library.upload.assignments.type", "Type"),
      id: t("attachments.library.upload.assignments.id", "Record ID"),
      href: t("attachments.library.upload.assignments.href", "Link"),
      label: t("attachments.library.upload.assignments.label", "Label"),
      add: t("attachments.library.upload.assignments.add", "Add assignment"),
      remove: t("attachments.library.upload.assignments.remove", "Remove")
    }),
    [t]
  );
  const formSchema = React.useMemo(
    () => z.object({
      files: z.array(z.any()).min(1, { message: t("attachments.library.upload.fileRequired", "Select at least one file to upload.") }),
      partitionCode: z.string().optional(),
      tags: z.array(z.string()).optional(),
      assignments: z.array(
        z.object({
          type: z.string().min(1),
          id: z.string().min(1),
          href: z.string().optional(),
          label: z.string().optional()
        })
      ).optional()
    }).passthrough(),
    [t]
  );
  const fields = React.useMemo(() => {
    return [
      {
        id: "files",
        label: t("attachments.library.upload.file", "Files"),
        type: "custom",
        component: (props) => /* @__PURE__ */ jsx(
          AttachmentFilesField,
          {
            ...props,
            uploading: isUploading,
            labels: {
              dropHint: t("attachments.library.upload.dropHint", "Drag and drop files here or click to upload."),
              choose: t("attachments.library.upload.choose", "Choose files"),
              uploading: t("attachments.library.upload.submitting", "Uploading\u2026"),
              empty: t("attachments.library.upload.noFiles", "No files selected yet.")
            }
          }
        )
      },
      {
        id: "partitionCode",
        label: t("attachments.library.upload.partition", "Partition"),
        type: "select",
        options: [
          { value: "", label: t("attachments.library.upload.partitionDefault", "Default (private)") },
          ...partitionOptions
        ]
      },
      {
        id: "tags",
        label: t("attachments.library.table.tags", "Tags"),
        type: "custom",
        component: ({ value, setValue, disabled }) => /* @__PURE__ */ jsx(
          TagsInput,
          {
            value: Array.isArray(value) ? value : [],
            onChange: (next) => setValue(next),
            suggestions: availableTags,
            placeholder: t("attachments.library.upload.tagsPlaceholder", "Add tags"),
            disabled: Boolean(disabled) || isUploading
          }
        )
      },
      {
        id: "assignments",
        label: "",
        type: "custom",
        component: ({ value, setValue, disabled }) => /* @__PURE__ */ jsx(
          AttachmentAssignmentsEditor,
          {
            value: Array.isArray(value) ? value : [],
            onChange: (next) => setValue(next),
            labels: assignmentLabels,
            disabled: Boolean(disabled) || isUploading
          }
        )
      }
    ];
  }, [assignmentLabels, availableTags, isUploading, partitionOptions, t]);
  const groups = React.useMemo(() => {
    return [
      {
        id: "details",
        title: t("attachments.library.upload.title", "Upload attachment"),
        column: 1,
        fields: ["files", "partitionCode", "tags", "assignments"]
      },
      {
        id: "customFields",
        title: t("entities.customFields.title", "Custom attributes"),
        column: 2,
        kind: "customFields"
      }
    ];
  }, [t]);
  const uploadPercentage = uploadProgress.total ? Math.min(100, Math.round(uploadProgress.completed / uploadProgress.total * 100)) : 0;
  const handleSubmit = React.useCallback(
    async (values) => {
      const files = Array.isArray(values.files) ? values.files : [];
      if (!files.length) {
        throw new Error(t("attachments.library.upload.fileRequired", "Select at least one file to upload."));
      }
      setUploadProgress({ completed: 0, total: files.length });
      setIsUploading(true);
      try {
        const tags = Array.isArray(values.tags) ? values.tags.map((tag) => typeof tag === "string" ? tag.trim() : "").filter((tag) => tag.length > 0) : [];
        const cleanedAssignments = Array.isArray(values.assignments) && values.assignments.length ? values.assignments.map((assignment) => ({
          type: assignment.type?.trim() ?? "",
          id: assignment.id?.trim() ?? "",
          href: assignment.href?.trim() || void 0,
          label: assignment.label?.trim() || void 0
        })).filter((assignment) => assignment.type && assignment.id) : [];
        const customFields = collectCustomFieldValues(values, {
          transform: (value) => normalizeCustomFieldSubmitValue(value)
        });
        let completed = 0;
        for (const file of files) {
          const fd = new FormData();
          fd.set("entityId", LIBRARY_ENTITY_ID);
          fd.set(
            "recordId",
            typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : String(Date.now())
          );
          fd.set("file", file);
          if (typeof values.partitionCode === "string" && values.partitionCode.trim().length) {
            fd.set("partitionCode", values.partitionCode.trim());
          }
          if (tags.length) fd.set("tags", JSON.stringify(tags));
          if (cleanedAssignments.length) fd.set("assignments", JSON.stringify(cleanedAssignments));
          if (Object.keys(customFields).length) fd.set("customFields", JSON.stringify(customFields));
          const call = await apiCall("/api/attachments", {
            method: "POST",
            body: fd
          });
          if (!call.ok) {
            const message = call.result?.error || t("attachments.library.upload.failed", "Upload failed.");
            throw new Error(message);
          }
          completed += 1;
          setUploadProgress({ completed, total: files.length });
        }
        flash(t("attachments.library.upload.success", "Attachment uploaded."), "success");
        onUploaded();
        onCancel();
      } catch (err) {
        const message = err?.message || t("attachments.library.upload.failed", "Upload failed.");
        flash(message, "error");
        throw new Error(message);
      } finally {
        setIsUploading(false);
      }
    },
    [onCancel, onUploaded, t]
  );
  return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
    /* @__PURE__ */ jsx(
      CrudForm,
      {
        embedded: true,
        schema: formSchema,
        entityId: E.attachments.attachment,
        fields,
        groups,
        initialValues: { files: [], tags: [], assignments: [], partitionCode: "" },
        submitLabel: isUploading ? t("attachments.library.upload.submitting", "Uploading\u2026") : t("attachments.library.upload.submit", "Upload"),
        extraActions: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: isUploading, children: t("attachments.library.upload.cancel", "Cancel") }),
        onSubmit: handleSubmit
      }
    ),
    isUploading ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 z-20 flex items-center justify-center bg-background/80 px-6 text-center backdrop-blur", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full max-w-sm flex-col items-center gap-4 rounded-xl border border-border/70 bg-card/95 px-6 py-8 shadow-2xl", children: [
      /* @__PURE__ */ jsx(Spinner, { size: "lg", className: "border-primary/50 border-t-primary" }),
      /* @__PURE__ */ jsxs("div", { className: "w-full space-y-3", children: [
        /* @__PURE__ */ jsx("p", { className: "text-base font-semibold", children: t("attachments.library.upload.progressLabel", "Uploading files") }),
        uploadProgress.total > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
          /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
            uploadProgress.completed,
            "/",
            uploadProgress.total
          ] }),
          /* @__PURE__ */ jsx("div", { className: "h-2 w-full rounded bg-muted", children: /* @__PURE__ */ jsx(
            "div",
            {
              className: "h-2 rounded bg-primary transition-all",
              style: {
                width: `${uploadPercentage}%`
              }
            }
          ) })
        ] }) : null
      ] })
    ] }) }) : null
  ] });
}
function AttachmentUploadDialog({ open, onOpenChange, partitions, availableTags, onUploaded }) {
  const t = useT();
  const [formResetKey, setFormResetKey] = React.useState(0);
  const previousOpen = React.useRef(open);
  React.useEffect(() => {
    if (previousOpen.current && !open) {
      setFormResetKey((prev) => prev + 1);
    }
    previousOpen.current = open;
  }, [open]);
  const handleDialogChange = React.useCallback(
    (next) => {
      onOpenChange(next);
    },
    [onOpenChange]
  );
  const handleUploaded = React.useCallback(() => {
    onUploaded();
  }, [onUploaded]);
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleDialogChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[54.6rem]", children: [
    /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("attachments.library.upload.title", "Upload attachment") }) }),
    /* @__PURE__ */ jsx(
      AttachmentUploadForm,
      {
        partitions,
        availableTags,
        onUploaded: handleUploaded,
        onCancel: () => handleDialogChange(false)
      },
      formResetKey
    )
  ] }) });
}
function AttachmentLibrary() {
  const t = useT();
  const queryClient = useQueryClient();
  const [page, setPage] = React.useState(1);
  const [search, setSearch] = React.useState("");
  const [filterValues, setFilterValues] = React.useState({});
  const [sorting, setSorting] = React.useState([{ id: "createdAt", desc: true }]);
  const [metadataDialogOpen, setMetadataDialogOpen] = React.useState(false);
  const [selectedRow, setSelectedRow] = React.useState(null);
  const [uploadDialogOpen, setUploadDialogOpen] = React.useState(false);
  const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false);
  const [deleteTarget, setDeleteTarget] = React.useState(null);
  const [deletePending, setDeletePending] = React.useState(false);
  const { data: featureCheckData } = useQuery({
    queryKey: ["attachments-feature-check"],
    queryFn: async () => {
      const call = await apiCall("/api/auth/feature-check", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ features: ["attachments.manage"] })
      });
      return call.result ?? {};
    },
    staleTime: 6e4
  });
  const canManage = hasFeature(featureCheckData?.granted, "attachments.manage");
  const filterSignature = React.useMemo(() => buildFilterSignature(filterValues), [filterValues]);
  const sortingSignature = React.useMemo(() => JSON.stringify(sorting), [sorting]);
  const { data, isLoading, error, refetch } = useQuery({
    queryKey: ["attachments-library", page, search, filterSignature, sortingSignature],
    queryFn: async () => {
      const params = new URLSearchParams();
      params.set("page", String(page));
      params.set("pageSize", String(PAGE_SIZE));
      if (search.trim().length > 0) params.set("search", search.trim());
      const partition = typeof filterValues.partition === "string" ? filterValues.partition : "";
      if (partition) params.set("partition", partition);
      const tags = Array.isArray(filterValues.tags) ? filterValues.tags : [];
      if (tags.length > 0) params.set("tags", tags.join(","));
      if (sorting.length > 0) {
        const primary = sorting[0];
        params.set("sortField", primary.id);
        params.set("sortDir", primary.desc ? "desc" : "asc");
      }
      const call = await apiCall(`/api/attachments/library?${params.toString()}`);
      if (!call.ok || !call.result) {
        const message = call.result?.error || t("attachments.library.errors.load", "Failed to load attachments.");
        throw new Error(message);
      }
      return call.result;
    }
  });
  const partitions = data?.partitions ?? [];
  const availableTags = data?.availableTags ?? [];
  const filters = React.useMemo(() => {
    const partitionOptions = partitions.map((entry) => ({
      value: entry.code,
      label: entry.title || entry.code
    }));
    return [
      {
        id: "partition",
        label: t("attachments.library.filters.partition", "Partition"),
        type: "select",
        options: partitionOptions
      },
      {
        id: "tags",
        label: t("attachments.library.filters.tags", "Tags"),
        type: "tags",
        placeholder: t("attachments.library.filters.tagsPlaceholder", "Filter by tag"),
        options: availableTags.map((tag) => ({ value: tag, label: tag }))
      }
    ];
  }, [availableTags, partitions, t]);
  const items = data?.items ?? [];
  const columns = React.useMemo(() => {
    return [
      {
        id: "preview",
        header: "",
        enableSorting: false,
        cell: ({ row }) => {
          const value = row.original;
          if (value.thumbnailUrl) {
            return /* @__PURE__ */ jsx("div", { className: "h-16 w-16 overflow-hidden rounded border bg-muted", children: /* @__PURE__ */ jsx(
              "img",
              {
                src: value.thumbnailUrl,
                alt: value.fileName,
                className: "h-full w-full object-cover",
                loading: "lazy"
              }
            ) });
          }
          const placeholder = resolveAttachmentPlaceholder(value.mimeType, value.fileName);
          const PlaceholderIcon = placeholder.icon;
          return /* @__PURE__ */ jsxs("div", { className: "flex h-16 w-16 flex-col items-center justify-center rounded border bg-muted text-overline font-semibold uppercase text-muted-foreground", children: [
            /* @__PURE__ */ jsx(PlaceholderIcon, { className: "mb-1 h-5 w-5 text-muted-foreground", "aria-hidden": true }),
            placeholder.label
          ] });
        }
      },
      {
        id: "fileName",
        accessorKey: "fileName",
        header: t("attachments.library.table.file", "File"),
        cell: ({ row }) => {
          const value = row.original;
          return /* @__PURE__ */ jsxs("div", { className: "space-y-1 min-w-0 max-w-[280px]", children: [
            /* @__PURE__ */ jsx("div", { className: "font-medium truncate", title: value.fileName, children: value.fileName }),
            /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
              formatFileSize(value.fileSize),
              " \u2022 ",
              value.mimeType || "application/octet-stream"
            ] }),
            /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground line-clamp-2", children: value.content?.trim() ? value.content : t("attachments.library.metadata.noContent", "No text extracted") })
          ] });
        }
      },
      {
        id: "tags",
        accessorKey: "tags",
        header: t("attachments.library.table.tags", "Tags"),
        enableSorting: false,
        cell: ({ row }) => {
          const tags = row.original.tags ?? [];
          if (!tags.length) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" });
          return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: tags.map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "outline", children: tag }, tag)) });
        }
      },
      {
        id: "assignments",
        accessorKey: "assignments",
        header: t("attachments.library.table.assignments", "Assignments"),
        enableSorting: false,
        cell: ({ row }) => {
          const assignments = filterLibraryAssignments(row.original.assignments);
          if (!assignments.length) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" });
          return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: assignments.map((assignment) => {
            const label = assignment.label?.trim() || assignment.id;
            const hideType = assignment.type === E.catalog?.catalog_product || assignment.type === E.catalog?.catalog_product_variant;
            const content = hideType ? label : `${assignment.type}: ${label}`;
            return assignment.href ? /* @__PURE__ */ jsx(
              "a",
              {
                href: assignment.href,
                className: "text-sm text-blue-600 underline",
                target: "_blank",
                rel: "noreferrer",
                children: content
              },
              `${assignment.type}-${assignment.id}-${assignment.href}`
            ) : /* @__PURE__ */ jsx("div", { className: "text-sm", children: content }, `${assignment.type}-${assignment.id}`);
          }) });
        }
      },
      {
        id: "partitionCode",
        accessorKey: "partitionCode",
        header: t("attachments.library.table.partition", "Partition"),
        cell: ({ row }) => /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: row.original.partitionTitle ?? row.original.partitionCode })
      },
      {
        id: "createdAt",
        accessorKey: "createdAt",
        header: t("attachments.library.table.created", "Created"),
        cell: ({ row }) => {
          const createdAt = row.original.createdAt;
          return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: createdAt ? humanDate(createdAt) : "\u2014" });
        }
      },
      {
        id: "download",
        header: t("attachments.library.table.download", "Download"),
        enableSorting: false,
        cell: ({ row }) => {
          const downloadPath = buildAttachmentFileUrl(row.original.id, { download: true });
          const absolute = resolveAbsoluteUrl(downloadPath);
          return /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", asChild: true, children: /* @__PURE__ */ jsx("a", { href: absolute, download: true, "aria-label": t("attachments.library.table.download", "Download"), children: /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" }) }) });
        }
      }
    ];
  }, [t]);
  const openMetadataDialog = React.useCallback((row) => {
    setSelectedRow(row);
    setMetadataDialogOpen(true);
  }, []);
  const openDeleteDialog = React.useCallback((row) => {
    setDeleteTarget(row);
    setDeleteDialogOpen(true);
  }, []);
  const handleMetadataSave = React.useCallback(
    async (id, payload) => {
      try {
        const body = {
          tags: payload.tags,
          assignments: payload.assignments
        };
        if (payload.customFields && Object.keys(payload.customFields).length) {
          body.customFields = payload.customFields;
        }
        const call = await apiCall(`/api/attachments/library/${encodeURIComponent(id)}`, {
          method: "PATCH",
          headers: { "content-type": "application/json" },
          body: JSON.stringify(body)
        });
        if (!call.ok) {
          const message = call.result?.error || t("attachments.library.metadata.error", "Failed to update metadata.");
          flash(message, "error");
          return;
        }
        flash(t("attachments.library.metadata.success", "Attachment updated."), "success");
        await queryClient.invalidateQueries({ queryKey: ["attachments-library"], exact: false });
        setMetadataDialogOpen(false);
      } catch (err) {
        flash(err?.message || t("attachments.library.metadata.error", "Failed to update metadata."), "error");
      }
    },
    [queryClient, t]
  );
  const handleUploadCompleted = React.useCallback(async () => {
    await queryClient.invalidateQueries({ queryKey: ["attachments-library"], exact: false });
  }, [queryClient]);
  const handleDelete = React.useCallback(async () => {
    if (!deleteTarget) return;
    try {
      setDeletePending(true);
      const call = await apiCall(
        `/api/attachments/library/${encodeURIComponent(deleteTarget.id)}`,
        { method: "DELETE" }
      );
      if (!call.ok) {
        const message = call.result?.error || t("attachments.library.errors.delete", "Failed to delete attachment.");
        flash(message, "error");
        return;
      }
      flash(t("attachments.library.messages.deleted", "Attachment removed."), "success");
      if (selectedRow?.id === deleteTarget.id) {
        setSelectedRow(null);
        setMetadataDialogOpen(false);
      }
      setDeleteDialogOpen(false);
      setDeleteTarget(null);
      await queryClient.invalidateQueries({ queryKey: ["attachments-library"], exact: false });
    } catch (err) {
      flash(err?.message || t("attachments.library.errors.delete", "Failed to delete attachment."), "error");
    } finally {
      setDeletePending(false);
    }
  }, [deleteTarget, queryClient, selectedRow, t]);
  const total = data?.total ?? 0;
  const totalPages = data?.totalPages ?? 0;
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx(
      DataTable,
      {
        stickyActionsColumn: true,
        title: t("attachments.library.title", "Attachments"),
        refreshButton: {
          label: t("attachments.library.actions.refresh", "Refresh"),
          onRefresh: () => {
            void refetch();
          },
          isRefreshing: isLoading
        },
        actions: canManage ? /* @__PURE__ */ jsx(Button, { onClick: () => setUploadDialogOpen(true), children: t("attachments.library.actions.upload", "Upload") }) : void 0,
        columns,
        data: items,
        sorting,
        onSortingChange: setSorting,
        rowActions: (row) => /* @__PURE__ */ jsx(
          RowActions,
          {
            items: [
              {
                id: "open",
                label: t("attachments.library.actions.open", "Open"),
                onSelect: () => {
                  if (!row.url) return;
                  window.open(row.url, "_blank", "noopener,noreferrer");
                }
              },
              {
                id: "edit",
                label: t("attachments.library.actions.edit", "Edit metadata"),
                onSelect: () => openMetadataDialog(row)
              },
              {
                id: "copy-url",
                label: t("attachments.library.actions.copyUrl", "Copy URL"),
                onSelect: () => {
                  if (!row.url) {
                    flash(t("attachments.library.actions.copyError", "Unable to copy link."), "error");
                    return;
                  }
                  const absolute = resolveAbsoluteUrl(row.url);
                  navigator.clipboard.writeText(absolute).then(
                    () => flash(
                      t("attachments.library.actions.copied", "Link copied."),
                      "success"
                    )
                  ).catch(
                    () => flash(
                      t("attachments.library.actions.copyError", "Unable to copy link."),
                      "error"
                    )
                  );
                }
              },
              {
                id: "delete",
                label: t("attachments.library.actions.delete", "Delete"),
                destructive: true,
                onSelect: () => openDeleteDialog(row)
              }
            ]
          }
        ),
        onRowClick: (row) => openMetadataDialog(row),
        isLoading,
        error: error?.message,
        emptyState: /* @__PURE__ */ jsx("div", { className: "py-10 text-center text-sm text-muted-foreground", children: t("attachments.library.table.empty", "No attachments found.") }),
        searchValue: search,
        onSearchChange: (value) => {
          setPage(1);
          setSearch(value);
        },
        searchPlaceholder: t("attachments.library.table.search", "Search files\u2026"),
        filters,
        filterValues,
        onFiltersApply: (values) => {
          setFilterValues(values);
          setPage(1);
        },
        onFiltersClear: () => {
          setFilterValues({});
          setPage(1);
        },
        pagination: {
          page,
          pageSize: PAGE_SIZE,
          total,
          totalPages,
          onPageChange: (next) => setPage(next)
        }
      }
    ),
    /* @__PURE__ */ jsx(
      AttachmentMetadataDialog,
      {
        open: metadataDialogOpen,
        onOpenChange: setMetadataDialogOpen,
        item: selectedRow,
        availableTags,
        onSave: handleMetadataSave
      }
    ),
    /* @__PURE__ */ jsx(
      AttachmentDeleteDialog,
      {
        open: deleteDialogOpen,
        onOpenChange: setDeleteDialogOpen,
        fileName: deleteTarget?.fileName,
        onConfirm: handleDelete,
        isDeleting: deletePending
      }
    ),
    /* @__PURE__ */ jsx(
      AttachmentUploadDialog,
      {
        open: uploadDialogOpen,
        onOpenChange: setUploadDialogOpen,
        partitions,
        availableTags,
        onUploaded: handleUploadCompleted
      }
    )
  ] });
}
export {
  AttachmentLibrary
};
//# sourceMappingURL=AttachmentLibrary.js.map
