"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import Link from "next/link";
import { DataTable } from "@open-mercato/ui/backend/DataTable";
import { ListEmptyState } from "@open-mercato/ui/backend/filters/ListEmptyState";
import { Button } from "@open-mercato/ui/primitives/button";
import { RowActions } from "@open-mercato/ui/backend/RowActions";
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { deleteCrud, buildCrudExportUrl } from "@open-mercato/ui/backend/utils/crud";
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
import { useCustomFieldDefs } from "@open-mercato/ui/backend/utils/customFieldDefs";
import { applyCustomFieldVisibility } from "@open-mercato/ui/backend/utils/customFieldColumns";
import { BooleanIcon } from "@open-mercato/ui/backend/ValueIcons";
import { markdownToPlainText } from "@open-mercato/ui/backend/markdown/markdownToPlainText";
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
import { useAppEvent } from "@open-mercato/ui/backend/injection/useAppEvent";
import { E } from "../../../../generated/entities.ids.generated.js";
import { ProductImageCell } from "./ProductImageCell.js";
const PAGE_SIZE = 25;
const ENTITY_ID = E.catalog.catalog_product;
function formatDate(value) {
  if (!value) return "\u2014";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "\u2014";
  return date.toLocaleDateString();
}
function renderOffers(offers) {
  if (!offers || offers.length === 0) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" });
  const visible = offers.slice(0, 3);
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", children: [
    visible.map((offer) => {
      const label = typeof offer.channelName === "string" && offer.channelName.trim().length ? offer.channelName.trim() : typeof offer.title === "string" && offer.title.trim().length ? offer.title.trim() : offer.channelId;
      const badgeTitle = typeof offer.channelCode === "string" && offer.channelCode.trim().length ? offer.channelCode : void 0;
      return /* @__PURE__ */ jsx(
        "span",
        {
          className: `inline-flex items-center rounded-full border px-2 py-0.5 text-xs ${offer.isActive ? "bg-secondary/80 text-secondary-foreground" : "bg-muted text-muted-foreground"}`,
          title: badgeTitle,
          children: label
        },
        offer.id
      );
    }),
    offers.length > visible.length ? /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
      "+",
      offers.length - visible.length
    ] }) : null
  ] });
}
function renderPrice(pricing, currency, fallback = "\u2014") {
  if (!pricing) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: fallback });
  const unit = pricing.unit_price_net ?? pricing.unit_price_gross;
  if (unit == null) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: fallback });
  const formatted = `${currency ?? pricing.currency_code ?? ""} ${unit}`;
  const kind = pricing.kind ?? "list";
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
    /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatted.trim() }),
    /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: kind })
  ] });
}
function ProductsDataTable({
  extraActions,
  onSnapshotChange
} = {}) {
  const t = useT();
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
  const scopeVersion = useOrganizationScopeVersion();
  const [rows, setRows] = React.useState([]);
  const [page, setPage] = React.useState(1);
  const [total, setTotal] = React.useState(0);
  const [totalPages, setTotalPages] = React.useState(1);
  const [cacheStatus, setCacheStatus] = React.useState(null);
  const [sorting, setSorting] = React.useState([{ id: "title", desc: false }]);
  const [search, setSearch] = React.useState("");
  const [filterValues, setFilterValues] = React.useState({});
  const [isLoading, setIsLoading] = React.useState(false);
  const [reloadToken, setReloadToken] = React.useState(0);
  useAppEvent("catalog.product.*", () => {
    setReloadToken((token) => token + 1);
  });
  const [customFieldsetFilter, setCustomFieldsetFilter] = React.useState(null);
  const { data: customFieldDefs = [] } = useCustomFieldDefs(ENTITY_ID, {
    keyExtras: [scopeVersion, reloadToken]
  });
  const [channelOptionsCache, setChannelOptionsCache] = React.useState({});
  const [categoryOptionsCache, setCategoryOptionsCache] = React.useState({});
  const [tagOptionsCache, setTagOptionsCache] = React.useState({});
  const registerOptions = React.useCallback(
    (setter, options) => {
      setter((prev) => {
        const next = { ...prev };
        options.forEach((opt) => {
          if (opt.value) next[opt.value] = opt;
        });
        return next;
      });
    },
    []
  );
  const registerChannelOptions = React.useCallback(
    (options) => registerOptions(setChannelOptionsCache, options),
    [registerOptions]
  );
  const registerCategoryOptions = React.useCallback(
    (options) => registerOptions(setCategoryOptionsCache, options),
    [registerOptions]
  );
  const registerTagOptions = React.useCallback(
    (options) => registerOptions(setTagOptionsCache, options),
    [registerOptions]
  );
  const channelOptions = React.useMemo(() => Object.values(channelOptionsCache), [channelOptionsCache]);
  const categoryOptions = React.useMemo(() => Object.values(categoryOptionsCache), [categoryOptionsCache]);
  const tagOptions = React.useMemo(() => Object.values(tagOptionsCache), [tagOptionsCache]);
  const loadChannelOptions = React.useCallback(
    async (term) => {
      try {
        const params = new URLSearchParams({ pageSize: "100", isActive: "true" });
        if (term && term.trim().length) params.set("search", term.trim());
        const payload = await readApiResultOrThrow(
          `/api/sales/channels?${params.toString()}`,
          void 0,
          { errorMessage: t("catalog.products.filters.channelsLoadError", "Failed to load channels") }
        );
        const items = Array.isArray(payload?.items) ? payload.items : [];
        const options = items.map((entry) => {
          const value = typeof entry.id === "string" ? entry.id : null;
          if (!value) return null;
          const label = typeof entry.name === "string" ? entry.name : typeof entry.code === "string" ? entry.code : value;
          return { value, label, description: typeof entry.code === "string" ? entry.code : void 0 };
        }).filter((option) => !!option);
        registerChannelOptions(options);
        return options;
      } catch {
        return [];
      }
    },
    [registerChannelOptions, t]
  );
  const loadCategoryOptions = React.useCallback(
    async (term) => {
      try {
        const params = new URLSearchParams({ pageSize: "200", view: "manage" });
        if (term && term.trim().length) params.set("search", term.trim());
        const payload = await readApiResultOrThrow(
          `/api/catalog/categories?${params.toString()}`,
          void 0,
          { errorMessage: t("catalog.products.filters.categoriesLoadError", "Failed to load categories") }
        );
        const items = Array.isArray(payload?.items) ? payload.items : [];
        const options = items.map((entry) => {
          const value = typeof entry.id === "string" ? entry.id : null;
          if (!value) return null;
          const label = typeof entry.name === "string" && entry.name.trim().length ? entry.name : value;
          const description = typeof entry.parentName === "string" && entry.parentName.trim().length ? entry.parentName : null;
          return { value, label, description };
        }).filter((option) => !!option);
        registerCategoryOptions(options);
        return options;
      } catch {
        return [];
      }
    },
    [registerCategoryOptions, t]
  );
  const loadTagOptions = React.useCallback(
    async (term) => {
      try {
        const params = new URLSearchParams({ pageSize: "100" });
        if (term && term.trim().length) params.set("search", term.trim());
        const payload = await readApiResultOrThrow(
          `/api/catalog/tags?${params.toString()}`,
          void 0,
          { errorMessage: t("catalog.products.filters.tagsLoadError", "Failed to load tags") }
        );
        const items = Array.isArray(payload?.items) ? payload.items : [];
        const options = items.map((entry) => {
          const value = typeof entry.id === "string" ? entry.id : null;
          if (!value) return null;
          const label = typeof entry.label === "string" && entry.label.trim().length ? entry.label : value;
          return { value, label };
        }).filter((option) => !!option);
        registerTagOptions(options);
        return options;
      } catch {
        return [];
      }
    },
    [registerTagOptions, t]
  );
  const productTypeOptions = React.useMemo(() => [
    { value: "simple", label: t("catalog.products.types.simple", "Simple") },
    { value: "configurable", label: t("catalog.products.types.configurable", "Configurable") },
    { value: "virtual", label: t("catalog.products.types.virtual", "Virtual") },
    { value: "downloadable", label: t("catalog.products.types.downloadable", "Downloadable") },
    {
      value: "bundle",
      label: `${t("catalog.products.types.bundle", "Bundle")} (${t("common.comingSoon", "Coming soon")})`
    },
    {
      value: "grouped",
      label: `${t("catalog.products.types.grouped", "Grouped")} (${t("common.comingSoon", "Coming soon")})`
    }
  ], [t]);
  const productTypeLabelMap = React.useMemo(() => {
    const map = /* @__PURE__ */ new Map();
    productTypeOptions.forEach((opt) => map.set(opt.value, opt.label));
    return map;
  }, [productTypeOptions]);
  const filters = React.useMemo(() => [
    { id: "status", label: t("catalog.products.filters.status"), type: "text" },
    { id: "isActive", label: t("catalog.products.filters.active"), type: "checkbox" },
    { id: "configurable", label: t("catalog.products.filters.configurable"), type: "checkbox" },
    { id: "productType", label: t("catalog.products.filters.productType", "Type"), type: "select", options: productTypeOptions },
    {
      id: "channelIds",
      label: t("catalog.products.filters.channels"),
      type: "tags",
      loadOptions: loadChannelOptions,
      options: channelOptions,
      formatValue: (val) => channelOptionsCache[val]?.label ?? val,
      formatDescription: (val) => channelOptionsCache[val]?.description ?? null
    },
    {
      id: "categoryIds",
      label: t("catalog.products.filters.categories", "Categories"),
      type: "tags",
      loadOptions: loadCategoryOptions,
      options: categoryOptions,
      formatValue: (val) => categoryOptionsCache[val]?.label ?? val,
      formatDescription: (val) => categoryOptionsCache[val]?.description ?? null
    },
    {
      id: "tagIds",
      label: t("catalog.products.filters.tags", "Tags"),
      type: "tags",
      loadOptions: loadTagOptions,
      options: tagOptions,
      formatValue: (val) => tagOptionsCache[val]?.label ?? val
    }
  ], [
    categoryOptions,
    categoryOptionsCache,
    channelOptions,
    channelOptionsCache,
    loadCategoryOptions,
    loadChannelOptions,
    loadTagOptions,
    productTypeOptions,
    tagOptions,
    tagOptionsCache,
    t
  ]);
  const columns = React.useMemo(() => {
    const base = [
      {
        id: "media",
        header: "",
        size: 80,
        cell: ({ row }) => /* @__PURE__ */ jsx(
          ProductImageCell,
          {
            mediaId: row.original.default_media_id,
            mediaUrl: row.original.default_media_url,
            title: row.original.title,
            cropType: "contain"
          }
        ),
        meta: { sticky: true }
      },
      {
        accessorKey: "title",
        header: t("catalog.products.table.title", "Title"),
        cell: ({ row }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
          /* @__PURE__ */ jsx("span", { className: "font-medium", children: row.original.title || "\u2014" }),
          row.original.subtitle ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: row.original.subtitle }) : null,
          row.original.handle ? /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
            "/",
            row.original.handle
          ] }) : null,
          row.original.description ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: markdownToPlainText(row.original.description) }) : null
        ] }),
        meta: { sticky: true }
      },
      {
        accessorKey: "sku",
        header: t("catalog.products.table.sku", "SKU"),
        cell: ({ getValue }) => {
          const value = getValue();
          return value ? /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: String(value) }) : /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" });
        }
      },
      {
        accessorKey: "product_type",
        header: t("catalog.products.table.type"),
        cell: ({ row }) => {
          const type = typeof row.original.product_type === "string" ? row.original.product_type : "simple";
          const label = productTypeLabelMap.get(type) ?? type;
          return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: label });
        }
      },
      {
        accessorKey: "is_configurable",
        header: t("catalog.products.table.configurable"),
        cell: ({ row }) => /* @__PURE__ */ jsx(BooleanIcon, { value: !!row.original.is_configurable })
      },
      {
        accessorKey: "is_active",
        header: t("catalog.products.table.active"),
        cell: ({ row }) => /* @__PURE__ */ jsx(BooleanIcon, { value: !!row.original.is_active })
      },
      {
        accessorKey: "pricing",
        header: t("catalog.products.table.price"),
        cell: ({ row }) => renderPrice(row.original.pricing, row.original.primary_currency_code)
      },
      {
        accessorKey: "offers",
        header: t("catalog.products.table.channels"),
        cell: ({ row }) => renderOffers(row.original.offers)
      },
      {
        accessorKey: "updated_at",
        header: t("catalog.products.table.updatedAt"),
        cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: formatDate(row.original.updated_at) })
      }
    ];
    return applyCustomFieldVisibility(base, customFieldDefs);
  }, [customFieldDefs, productTypeLabelMap, t]);
  const handleSearchChange = React.useCallback((value) => {
    setSearch(value);
    setPage(1);
  }, []);
  const handleFiltersApply = React.useCallback((values) => {
    setFilterValues(values);
    setPage(1);
  }, []);
  const handleFiltersClear = React.useCallback(() => {
    setFilterValues({});
    setPage(1);
  }, []);
  const handleCustomFieldsetFilterChange = React.useCallback(
    (value) => {
      if (value === customFieldsetFilter) return;
      setCustomFieldsetFilter(value);
      setFilterValues((prev) => {
        const entries = Object.entries(prev);
        if (!entries.some(([key]) => key.startsWith("cf_"))) return prev;
        const next = {};
        entries.forEach(([key, val]) => {
          if (!key.startsWith("cf_")) next[key] = val;
        });
        return next;
      });
      setPage(1);
    },
    [customFieldsetFilter]
  );
  const handleRefresh = React.useCallback(() => {
    setReloadToken((token) => token + 1);
  }, []);
  const queryParams = React.useMemo(() => {
    const params = new URLSearchParams();
    params.set("page", String(page));
    params.set("pageSize", String(PAGE_SIZE));
    if (search.trim()) params.set("search", search.trim());
    const sort = sorting[0];
    if (sort?.id) {
      params.set("sortField", sort.id);
      params.set("sortDir", sort.desc ? "desc" : "asc");
    }
    const status = filterValues.status;
    if (typeof status === "string" && status.trim()) {
      params.set("status", status.trim());
    }
    if (filterValues.isActive === true) params.set("isActive", "true");
    if (filterValues.isActive === false) params.set("isActive", "false");
    if (filterValues.configurable === true) params.set("configurable", "true");
    if (filterValues.configurable === false) params.set("configurable", "false");
    if (typeof filterValues.productType === "string" && filterValues.productType.trim()) {
      params.set("productType", filterValues.productType.trim());
    }
    if (Array.isArray(filterValues.channelIds) && filterValues.channelIds.length) {
      const values = filterValues.channelIds.map((value) => typeof value === "string" ? value : null).filter((value) => !!value);
      if (values.length) params.set("channelIds", values.join(","));
    }
    if (Array.isArray(filterValues.categoryIds) && filterValues.categoryIds.length) {
      const values = filterValues.categoryIds.map((value) => typeof value === "string" ? value : null).filter((value) => !!value);
      if (values.length) params.set("categoryIds", values.join(","));
    }
    if (Array.isArray(filterValues.tagIds) && filterValues.tagIds.length) {
      const values = filterValues.tagIds.map((value) => typeof value === "string" ? value : null).filter((value) => !!value);
      if (values.length) params.set("tagIds", values.join(","));
    }
    Object.entries(filterValues).forEach(([key, value]) => {
      if (!key.startsWith("cf_") || value == null) return;
      if (Array.isArray(value)) {
        const entries = value.map((entry) => typeof entry === "string" ? entry.trim() : String(entry || "").trim()).filter((entry) => entry.length > 0);
        if (entries.length) params.set(key, entries.join(","));
      } else if (typeof value === "object" && value !== null && ("from" in value || "to" in value)) {
        const range = value;
        if (typeof range.from === "string" && range.from.trim().length) {
          params.set(`${key}:from`, range.from.trim());
        }
        if (typeof range.to === "string" && range.to.trim().length) {
          params.set(`${key}:to`, range.to.trim());
        }
      } else if (typeof value === "string" && value.trim()) {
        params.set(key, value.trim());
      }
    });
    if (typeof customFieldsetFilter === "string" && customFieldsetFilter.trim().length > 0) {
      params.set("customFieldset", customFieldsetFilter.trim());
    }
    return params.toString();
  }, [customFieldsetFilter, filterValues, page, search, sorting]);
  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      setIsLoading(true);
      setCacheStatus(null);
      try {
        const fallback = { items: [], total: 0, totalPages: 1 };
        const call = await apiCall(
          `/api/catalog/products?${queryParams}`,
          void 0,
          { fallback }
        );
        if (!call.ok) {
          const message = t("catalog.products.list.error.load", "Failed to load products");
          flash(message, "error");
          if (!cancelled) setCacheStatus(null);
          return;
        }
        const payload = call.result ?? fallback;
        if (cancelled) return;
        setCacheStatus(call.cacheStatus ?? null);
        const items = Array.isArray(payload.items) ? payload.items : [];
        const normalized = items.filter((item) => typeof item?.id === "string");
        setRows(normalized);
        setTotal(typeof payload.total === "number" ? payload.total : normalized.length);
        setTotalPages(typeof payload.totalPages === "number" ? payload.totalPages : 1);
      } catch (error) {
        if (!cancelled) {
          setCacheStatus(null);
          const message = error instanceof Error ? error.message : t("catalog.products.list.error.load", "Failed to load products");
          flash(message, "error");
        }
      } finally {
        if (!cancelled) setIsLoading(false);
      }
    }
    load();
    return () => {
      cancelled = true;
    };
  }, [queryParams, reloadToken, scopeVersion, t]);
  const handleDelete = React.useCallback(async (row) => {
    const confirmed = await confirm({
      title: t("catalog.products.list.deleteConfirm", "Delete this product?"),
      variant: "destructive"
    });
    if (!confirmed) return;
    try {
      const headers = buildOptimisticLockHeader(typeof row.updated_at === "string" ? row.updated_at : null);
      await withScopedApiRequestHeaders(headers, () => deleteCrud("catalog/products", row.id, {
        errorMessage: t("catalog.products.list.error.delete", "Failed to delete product")
      }));
      flash(t("catalog.products.flash.deleted", "Product deleted"), "success");
      setReloadToken((token) => token + 1);
    } catch (error) {
      const message = error instanceof Error ? error.message : t("catalog.products.list.error.delete", "Failed to delete product");
      flash(message, "error");
    }
  }, [confirm, t]);
  React.useEffect(() => {
    if (!onSnapshotChange) return;
    onSnapshotChange({ search, filterValues, total });
  }, [onSnapshotChange, search, filterValues, total]);
  const currentParams = React.useMemo(() => Object.fromEntries(new URLSearchParams(queryParams)), [queryParams]);
  const exportConfig = React.useMemo(() => ({
    view: {
      getUrl: (format) => buildCrudExportUrl("catalog/products", { ...currentParams, exportScope: "view" }, format)
    },
    full: {
      getUrl: (format) => buildCrudExportUrl("catalog/products", { ...currentParams, exportScope: "full", all: "true" }, format)
    }
  }), [currentParams]);
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx(
      DataTable,
      {
        title: t("catalog.products.page.title", "Products & services"),
        entityId: ENTITY_ID,
        customFieldFilterKeyExtras: [scopeVersion, reloadToken],
        refreshButton: {
          label: t("catalog.products.actions.refresh", "Refresh"),
          onRefresh: handleRefresh,
          isRefreshing: isLoading
        },
        actions: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
          extraActions,
          /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsx(Link, { href: "/backend/catalog/products/create", children: t("catalog.products.actions.create", "Create") }) })
        ] }),
        columns,
        data: rows,
        emptyState: /* @__PURE__ */ jsx(
          ListEmptyState,
          {
            entityName: t("catalog.products.page.title", "Products & services"),
            createHref: "/backend/catalog/products/create",
            createLabel: t("catalog.products.actions.create", "Create")
          }
        ),
        searchValue: search,
        onSearchChange: handleSearchChange,
        filters,
        filterValues,
        onFiltersApply: handleFiltersApply,
        onFiltersClear: handleFiltersClear,
        onCustomFieldFilterFieldsetChange: handleCustomFieldsetFilterChange,
        sorting,
        onSortingChange: setSorting,
        injectionSpotId: "data-table:catalog.products",
        injectionContext: {
          search,
          filters: filterValues,
          customFieldset: customFieldsetFilter,
          page,
          sorting,
          scopeVersion,
          // Step 5.15: surface `total` so the merchandising AI widget
          // (rendered in `data-table:catalog.products:header`) can build
          // a selection-aware pageContext per spec §10.1 without taking a
          // dependency on the host page.
          total,
          totalMatching: total
        },
        pagination: {
          page,
          pageSize: PAGE_SIZE,
          total,
          totalPages,
          onPageChange: setPage,
          cacheStatus
        },
        exporter: exportConfig,
        isLoading,
        perspective: { tableId: "catalog.products.list" },
        stickyActionsColumn: true,
        rowActions: (row) => /* @__PURE__ */ jsx(
          RowActions,
          {
            items: [
              {
                id: "edit",
                label: t("catalog.products.table.actions.edit", "Edit"),
                href: `/backend/catalog/products/${row.id}`
              },
              {
                id: "delete",
                label: t("catalog.products.table.actions.delete", "Delete"),
                destructive: true,
                onSelect: () => {
                  void handleDelete(row);
                }
              }
            ]
          }
        )
      }
    ),
    ConfirmDialogElement
  ] });
}
export {
  ProductsDataTable as default
};
//# sourceMappingURL=ProductsDataTable.js.map
