"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { CreditCard } from "lucide-react";
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
import { LookupSelect } from "@open-mercato/ui/backend/inputs";
import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
import { createCrud, updateCrud } from "@open-mercato/ui/backend/utils/crud";
import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
import { handleSectionMutationError } from "./optimisticLock.js";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler";
import { Input } from "@open-mercato/ui/primitives/input";
import { Spinner } from "@open-mercato/ui/primitives/spinner";
import { E } from "../../../../generated/entities.ids.generated.js";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { normalizeCustomFieldSubmitValue, extractCustomFieldValues } from "./customFieldHelpers.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("sales");
const normalizeNumber = (value) => {
  if (typeof value === "number" && Number.isFinite(value)) return value;
  if (typeof value === "string" && value.trim().length) {
    const parsed = Number(value);
    if (!Number.isNaN(parsed)) return parsed;
  }
  return 0;
};
function PaymentDialog({
  open,
  mode,
  payment,
  currencyCode,
  orderId,
  organizationId,
  tenantId,
  documentUpdatedAt,
  onOpenChange,
  onSaved
}) {
  const t = useT();
  const dialogContentRef = React.useRef(null);
  const [formResetKey, setFormResetKey] = React.useState(0);
  const [paymentMethods, setPaymentMethods] = React.useState([]);
  const [methodsLoading, setMethodsLoading] = React.useState(false);
  const [paymentStatuses, setPaymentStatuses] = React.useState([]);
  const [paymentStatusLoading, setPaymentStatusLoading] = React.useState(false);
  const [documentStatuses, setDocumentStatuses] = React.useState([]);
  const [documentStatusLoading, setDocumentStatusLoading] = React.useState(false);
  const currencyLabel = React.useMemo(() => {
    const code = currencyCode ? currencyCode.toUpperCase() : "";
    if (!code) return t("sales.documents.detail.empty", "Not set");
    return code;
  }, [currencyCode, t]);
  const initialValues = React.useMemo(
    () => ({
      amount: payment?.amount ?? "",
      paymentMethodId: payment?.paymentMethodId ?? "",
      paymentReference: payment?.paymentReference ?? "",
      receivedAt: payment?.receivedAt ? payment.receivedAt.slice(0, 10) : "",
      statusEntryId: payment?.statusEntryId ?? "",
      documentStatusEntryId: "",
      customFieldSetId: payment?.customFieldSetId ?? "",
      ...extractCustomFieldValues(payment)
    }),
    [
      payment?.amount,
      payment?.customFieldSetId,
      payment?.customValues,
      payment?.paymentMethodId,
      payment?.paymentReference,
      payment?.receivedAt,
      payment?.statusEntryId
    ]
  );
  const loadPaymentMethods = React.useCallback(
    async (query) => {
      setMethodsLoading(true);
      try {
        const params = new URLSearchParams({ page: "1", pageSize: "100", isActive: "true" });
        if (query && query.trim().length) params.set("search", query.trim());
        const response = await apiCall(
          `/api/sales/payment-methods?${params.toString()}`,
          void 0,
          { fallback: { items: [] } }
        );
        if (response.ok && Array.isArray(response.result?.items)) {
          const options = response.result.items.map((item) => {
            const id = typeof item.id === "string" ? item.id : null;
            if (!id) return null;
            const name = typeof item.name === "string" ? item.name : null;
            const code = typeof item.code === "string" ? item.code : null;
            return {
              id,
              name: name ?? code ?? id,
              code: code ?? id
            };
          }).filter((entry) => !!entry);
          if (!query) setPaymentMethods(options);
          return options;
        }
        if (!query) setPaymentMethods([]);
        return [];
      } catch (err) {
        logger.error("sales.payments.methods.load", { err });
        return [];
      } finally {
        setMethodsLoading(false);
      }
    },
    []
  );
  const fetchPaymentMethodItems = React.useCallback(
    async (query) => {
      const options = paymentMethods.length && !query ? paymentMethods : await loadPaymentMethods(query);
      const term = query?.trim().toLowerCase() ?? "";
      return options.filter(
        (option) => !term.length || option.name.toLowerCase().includes(term) || option.code.toLowerCase().includes(term)
      ).map((option) => ({
        id: option.id,
        title: option.name,
        subtitle: option.code,
        icon: /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
      }));
    },
    [loadPaymentMethods, paymentMethods]
  );
  const shortcutLabel = t("sales.documents.payments.saveShortcut", "Save \u2318\u23CE / Ctrl+Enter");
  const renderStatusIcon = React.useCallback(
    (color) => /* @__PURE__ */ jsx(
      "span",
      {
        className: "h-2.5 w-2.5 rounded-full border border-border/70",
        style: color ? { backgroundColor: color, borderColor: color } : void 0
      }
    ),
    []
  );
  const loadDocumentStatuses = React.useCallback(async () => {
    setDocumentStatusLoading(true);
    try {
      const params = new URLSearchParams({ page: "1", pageSize: "100" });
      const response = await apiCall(
        `/api/sales/order-statuses?${params.toString()}`,
        void 0,
        { fallback: { items: [] } }
      );
      const items = Array.isArray(response.result?.items) ? response.result.items : [];
      const mapped = items.map((entry) => {
        const id = typeof entry.id === "string" ? entry.id : null;
        const value = typeof entry.value === "string" ? entry.value : null;
        if (!id || !value) return null;
        const label = typeof entry.label === "string" && entry.label.trim().length ? entry.label : value;
        const color = typeof entry.color === "string" && entry.color.trim().length ? entry.color : null;
        return { id, value, label, color };
      }).filter((entry) => Boolean(entry));
      setDocumentStatuses(mapped);
      return mapped;
    } catch (err) {
      logger.error("sales.payments.statuses.load", { err });
      setDocumentStatuses([]);
      return [];
    } finally {
      setDocumentStatusLoading(false);
    }
  }, []);
  const loadPaymentStatuses = React.useCallback(async () => {
    setPaymentStatusLoading(true);
    try {
      const params = new URLSearchParams({ page: "1", pageSize: "100" });
      const response = await apiCall(
        `/api/sales/payment-statuses?${params.toString()}`,
        void 0,
        { fallback: { items: [] } }
      );
      const items = Array.isArray(response.result?.items) ? response.result.items : [];
      const mapped = items.map((entry) => {
        const id = typeof entry.id === "string" ? entry.id : null;
        const value = typeof entry.value === "string" ? entry.value : null;
        if (!id || !value) return null;
        const label = typeof entry.label === "string" && entry.label.trim().length ? entry.label : value;
        const color = typeof entry.color === "string" && entry.color.trim().length ? entry.color : null;
        return { id, value, label, color };
      }).filter((entry) => Boolean(entry));
      setPaymentStatuses(mapped);
      return mapped;
    } catch (err) {
      logger.error("sales.payments.statuses.load", { err });
      setPaymentStatuses([]);
      return [];
    } finally {
      setPaymentStatusLoading(false);
    }
  }, []);
  React.useEffect(() => {
    if (!open) return;
    setFormResetKey((prev) => prev + 1);
    if (!paymentMethods.length) {
      void loadPaymentMethods();
    }
    if (!paymentStatuses.length) {
      void loadPaymentStatuses();
    }
    if (mode === "create") {
      if (!documentStatuses.length) {
        void loadDocumentStatuses();
      }
    }
  }, [
    documentStatuses.length,
    loadDocumentStatuses,
    loadPaymentStatuses,
    loadPaymentMethods,
    mode,
    open,
    payment?.id,
    paymentStatuses.length,
    paymentMethods.length
  ]);
  const fetchDocumentStatusItems = React.useCallback(
    async (query) => {
      const options = documentStatuses.length && !query ? documentStatuses : await loadDocumentStatuses();
      const term = query?.trim().toLowerCase() ?? "";
      return options.filter(
        (option) => !term.length || option.label.toLowerCase().includes(term) || option.value.toLowerCase().includes(term)
      ).map((option) => ({
        id: option.id,
        title: option.label,
        subtitle: option.value,
        icon: renderStatusIcon(option.color)
      }));
    },
    [documentStatuses, loadDocumentStatuses, renderStatusIcon]
  );
  const fetchPaymentStatusItems = React.useCallback(
    async (query) => {
      const options = paymentStatuses.length && !query ? paymentStatuses : await loadPaymentStatuses();
      const term = query?.trim().toLowerCase() ?? "";
      return options.filter(
        (option) => !term.length || option.label.toLowerCase().includes(term) || option.value.toLowerCase().includes(term)
      ).map((option) => ({
        id: option.id,
        title: option.label,
        subtitle: option.value,
        icon: renderStatusIcon(option.color)
      }));
    },
    [loadPaymentStatuses, paymentStatuses, renderStatusIcon]
  );
  const fields = React.useMemo(
    () => [
      {
        id: "amount",
        label: t("sales.documents.payments.amount", "Amount"),
        type: "custom",
        required: true,
        component: ({ value, setValue }) => {
          const normalized = typeof value === "number" ? value : typeof value === "string" ? value : "";
          return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
            /* @__PURE__ */ jsx(
              Input,
              {
                type: "number",
                inputMode: "decimal",
                step: "0.01",
                value: normalized,
                onChange: (event) => setValue(event.target.value),
                placeholder: "0.00"
              }
            ),
            /* @__PURE__ */ jsx("span", { className: "rounded-full border border-border/70 bg-muted/50 px-3 py-1 text-xs font-semibold uppercase text-foreground", children: currencyLabel })
          ] });
        }
      },
      {
        id: "paymentMethodId",
        label: t("sales.documents.payments.method", "Method"),
        type: "custom",
        component: ({ value, setValue }) => {
          const currentValue = typeof value === "string" && value.length ? value : null;
          return /* @__PURE__ */ jsx(
            LookupSelect,
            {
              value: currentValue,
              onChange: (next) => setValue(next ?? ""),
              fetchItems: fetchPaymentMethodItems,
              searchPlaceholder: t("sales.documents.payments.methodPlaceholder", "Search payment method"),
              emptyLabel: t("sales.documents.payments.methodsEmpty", "No payment methods"),
              loadingLabel: t("sales.documents.payments.loadingMethods", "Loading payment methods\u2026"),
              selectedHintLabel: (id) => t("sales.documents.payments.methodSelected", "Selected method: {{id}}", { id }),
              minQuery: 0
            }
          );
        }
      },
      {
        id: "statusEntryId",
        label: t("sales.documents.payments.status", "Status"),
        type: "custom",
        component: ({ value, setValue }) => {
          const currentValue = typeof value === "string" && value.length ? value : null;
          return /* @__PURE__ */ jsx(
            LookupSelect,
            {
              value: currentValue,
              onChange: (next) => setValue(next ?? ""),
              fetchItems: fetchPaymentStatusItems,
              placeholder: t("sales.documents.payments.statusPlaceholder", "Select status"),
              loading: paymentStatusLoading,
              minQuery: 0
            }
          );
        }
      },
      ...mode === "create" ? [
        {
          id: "documentStatusEntryId",
          label: t("sales.documents.status.changeDocument", "Change order/quote status"),
          type: "custom",
          component: ({ value, setValue }) => {
            const currentValue = typeof value === "string" && value.length ? value : null;
            return /* @__PURE__ */ jsx(
              LookupSelect,
              {
                value: currentValue,
                onChange: (next) => setValue(next ?? ""),
                fetchItems: fetchDocumentStatusItems,
                placeholder: t(
                  "sales.documents.status.documentPlaceholder",
                  "Select new order/quote status"
                ),
                loading: documentStatusLoading,
                minQuery: 0
              }
            );
          }
        }
      ] : [],
      {
        id: "paymentReference",
        label: t("sales.documents.payments.reference", "Reference"),
        type: "text",
        placeholder: t("sales.documents.payments.referencePlaceholder", "External reference or note")
      },
      {
        id: "receivedAt",
        label: t("sales.documents.payments.receivedAt", "Received at"),
        type: "date"
      }
    ],
    [
      currencyLabel,
      documentStatusLoading,
      fetchPaymentStatusItems,
      fetchDocumentStatusItems,
      fetchPaymentMethodItems,
      paymentStatusLoading,
      mode,
      t
    ]
  );
  const groups = React.useMemo(
    () => {
      const base = [
        {
          id: "paymentDetails",
          title: t("sales.documents.payments.form.title", "Payment details"),
          column: 1,
          fields: ["amount", "paymentMethodId", "statusEntryId"]
        }
      ];
      if (mode === "create") {
        base.push({
          id: "statusChanges",
          title: t("sales.documents.status.sectionTitle", "Status changes"),
          column: 1,
          fields: ["documentStatusEntryId"]
        });
      }
      base.push({
        id: "paymentReference",
        title: t("sales.documents.payments.reference", "Reference"),
        column: 2,
        fields: ["paymentReference", "receivedAt"]
      });
      base.push({
        id: "paymentCustomFields",
        title: t("entities.customFields.title", "Custom fields"),
        column: 2,
        kind: "customFields"
      });
      return base;
    },
    [mode, t]
  );
  const handleSubmit = React.useCallback(
    async (values) => {
      const resolvedCurrency = currencyCode ? currencyCode.toUpperCase() : "";
      const amountValue = normalizeNumber(values.amount);
      if (!resolvedCurrency.trim()) {
        throw createCrudFormError(t("sales.documents.payments.currencyRequired", "Currency is required."));
      }
      if (amountValue <= 0) {
        throw createCrudFormError(t("sales.documents.payments.amountRequired", "Enter a positive amount."), {
          amount: t("sales.documents.payments.amountRequired", "Enter a positive amount.")
        });
      }
      const payload = {
        orderId,
        amount: amountValue,
        currencyCode: resolvedCurrency,
        paymentReference: typeof values.paymentReference === "string" && values.paymentReference.trim().length ? values.paymentReference.trim() : void 0,
        paymentMethodId: typeof values.paymentMethodId === "string" && values.paymentMethodId.trim().length ? values.paymentMethodId : void 0,
        statusEntryId: typeof values.statusEntryId === "string" && values.statusEntryId.trim().length ? values.statusEntryId : void 0,
        customFieldSetId: typeof values.customFieldSetId === "string" && values.customFieldSetId.trim().length ? values.customFieldSetId.trim() : void 0,
        organizationId: organizationId ?? void 0,
        tenantId: tenantId ?? void 0
      };
      const documentStatusEntryId = typeof values.documentStatusEntryId === "string" && values.documentStatusEntryId.trim().length ? values.documentStatusEntryId : null;
      if (documentStatusEntryId) {
        payload.documentStatusEntryId = documentStatusEntryId;
      }
      if (typeof values.receivedAt === "string" && values.receivedAt.trim().length) {
        payload.receivedAt = new Date(values.receivedAt);
      }
      const customFields = collectCustomFieldValues(values, {
        transform: normalizeCustomFieldSubmitValue
      });
      if (Object.keys(customFields).length) payload.customFields = customFields;
      const action = payment?.id ? updateCrud : createCrud;
      try {
        const result = await withScopedApiRequestHeaders(
          // The server guards the PARENT order's aggregate version (Gap A) for
          // both create and update, so send the order's `updated_at`.
          buildOptimisticLockHeader(documentUpdatedAt ?? void 0),
          () => action(
            "sales/payments",
            payment?.id ? { id: payment.id, ...payload } : payload,
            {
              errorMessage: t("sales.documents.payments.errorSave", "Failed to save payment.")
            }
          )
        );
        if (result.ok) {
          const totals = result.result?.orderTotals;
          if (onSaved) {
            await onSaved(totals ?? null);
          }
          setFormResetKey((prev) => prev + 1);
          onOpenChange(false);
        }
      } catch (err) {
        if (handleSectionMutationError(err, t, () => {
          if (onSaved) void onSaved();
        })) {
          onOpenChange(false);
          return;
        }
        throw err;
      }
    },
    [currencyCode, documentUpdatedAt, mode, onOpenChange, onSaved, orderId, organizationId, payment?.id, t, tenantId]
  );
  const handleSubmitForm = React.useCallback(
    () => dialogContentRef.current?.querySelector("form")?.requestSubmit(),
    []
  );
  const handleKeyDown = useDialogKeyHandler({
    onConfirm: handleSubmitForm,
    onCancel: () => onOpenChange(false)
  });
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
    DialogContent,
    {
      ref: dialogContentRef,
      className: "sm:max-w-5xl",
      onKeyDown: handleKeyDown,
      children: [
        /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: mode === "edit" ? t("sales.documents.payments.edit", "Edit payment") : t("sales.documents.payments.add", "Add payment") }) }),
        /* @__PURE__ */ jsx(
          CrudForm,
          {
            embedded: true,
            entityId: E.sales.sales_payment,
            fields,
            groups,
            initialValues,
            customFieldsetBindings: { [E.sales.sales_payment]: { valueKey: "customFieldSetId" } },
            submitLabel: shortcutLabel,
            onSubmit: handleSubmit,
            loadingMessage: t("sales.documents.payments.loading", "Loading payments\u2026"),
            customFieldsLoadingMessage: t("ui.forms.loading", "Loading data..."),
            contentHeader: methodsLoading ? /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
              /* @__PURE__ */ jsx(Spinner, { className: "h-3.5 w-3.5 animate-spin" }),
              t("sales.documents.payments.loadingMethods", "Loading payment methods\u2026")
            ] }) : null
          },
          formResetKey
        )
      ]
    }
  ) });
}
export {
  PaymentDialog
};
//# sourceMappingURL=PaymentDialog.js.map
