"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { Badge } from "@open-mercato/ui/primitives/badge";
import { DataTable } from "@open-mercato/ui/backend/DataTable";
import { ErrorMessage, LoadingMessage, TabEmptyState } from "@open-mercato/ui/backend/detail";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
import { createCrud, deleteCrud, updateCrud } from "@open-mercato/ui/backend/utils/crud";
import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
import { handleSectionMutationError } from "./optimisticLock.js";
import { RowActions } from "@open-mercato/ui/backend/RowActions";
import {
  emitSalesDocumentTotalsRefresh,
  subscribeSalesDocumentTotalsRefresh
} from "@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents";
import { PriceWithCurrency } from "../PriceWithCurrency.js";
import { AdjustmentDialog } from "./AdjustmentDialog.js";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { useOrganizationScopeDetail } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
import { extractCustomFieldValues } from "./customFieldHelpers.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("sales");
const FALLBACK_ADJUSTMENT_KIND_VALUES = [
  "discount",
  "tax",
  "shipping",
  "surcharge",
  "custom"
];
function normalizeNumber(value, fallback = 0) {
  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 fallback;
}
function formatPercent(value) {
  if (value === null || value === void 0) return "\u2014";
  const formatter = new Intl.NumberFormat(void 0, { style: "percent", maximumFractionDigits: 2 });
  return formatter.format(value / 100);
}
function SalesDocumentAdjustmentsSection({
  documentId,
  kind,
  currencyCode,
  documentUpdatedAt,
  organizationId: orgFromProps,
  tenantId: tenantFromProps,
  onActionChange,
  onRowsChange
}) {
  const t = useT();
  const { organizationId, tenantId } = useOrganizationScopeDetail();
  const resolvedOrganizationId = orgFromProps ?? organizationId ?? null;
  const resolvedTenantId = tenantFromProps ?? tenantId ?? null;
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [dialogOpen, setDialogOpen] = React.useState(false);
  const [activeAdjustment, setActiveAdjustment] = React.useState(null);
  const [kindOptions, setKindOptions] = React.useState([]);
  const kindLoadingRef = React.useRef(false);
  const apiResourcePath = React.useMemo(
    () => kind === "order" ? "/api/sales/order-adjustments" : "/api/sales/quote-adjustments",
    [kind]
  );
  const crudResourcePath = React.useMemo(
    () => kind === "order" ? "sales/order-adjustments" : "sales/quote-adjustments",
    [kind]
  );
  const documentKey = kind === "order" ? "orderId" : "quoteId";
  const fallbackKindOptions = React.useMemo(
    () => FALLBACK_ADJUSTMENT_KIND_VALUES.map((value) => ({
      value,
      label: t(`sales.documents.adjustments.kindLabels.${value}`, value),
      color: null,
      icon: null
    })),
    [t]
  );
  const kindOptionMap = React.useMemo(
    () => kindOptions.reduce((acc, entry) => {
      acc[entry.value] = entry;
      return acc;
    }, {}),
    [kindOptions]
  );
  const loadKindOptions = React.useCallback(async () => {
    if (kindOptions.length) return kindOptions;
    if (kindLoadingRef.current) return kindOptions.length ? kindOptions : fallbackKindOptions;
    kindLoadingRef.current = true;
    try {
      const params = new URLSearchParams({ page: "1", pageSize: "100" });
      const response = await apiCall(
        `/api/sales/adjustment-kinds?${params.toString()}`,
        void 0,
        { fallback: { items: [] } }
      );
      const items = Array.isArray(response.result?.items) ? response.result.items : [];
      const parsed = items.map((item) => {
        const value = typeof item.value === "string" ? item.value.trim() : "";
        if (!value) return null;
        const label = typeof item.label === "string" && item.label.trim().length ? item.label.trim() : value;
        const color = typeof item.color === "string" && /^#([0-9a-fA-F]{6})$/.test(item.color) ? `#${item.color.slice(1).toLowerCase()}` : null;
        const icon = typeof item.icon === "string" && item.icon.trim().length ? item.icon.trim() : null;
        return { value, label, color, icon };
      }).filter((entry) => Boolean(entry));
      const merged = /* @__PURE__ */ new Map();
      fallbackKindOptions.forEach((entry) => merged.set(entry.value, entry));
      parsed.forEach((entry) => merged.set(entry.value, entry));
      const options = Array.from(merged.values()).sort(
        (a, b) => a.label.localeCompare(b.label, void 0, { sensitivity: "base" })
      );
      setKindOptions(options);
      kindLoadingRef.current = false;
      return options;
    } catch (err) {
      logger.error("sales.adjustment-kinds.fetch", { err });
      kindLoadingRef.current = false;
      setKindOptions(fallbackKindOptions);
      return fallbackKindOptions;
    }
  }, [fallbackKindOptions, kindOptions]);
  React.useEffect(() => {
    loadKindOptions().catch(() => {
    });
  }, [loadKindOptions, resolvedOrganizationId, resolvedTenantId]);
  const loadAdjustments = React.useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const params = new URLSearchParams({ page: "1", pageSize: "100", [documentKey]: documentId });
      const response = await apiCall(
        `${apiResourcePath}?${params.toString()}`,
        void 0,
        { fallback: { items: [] } }
      );
      const items = Array.isArray(response.result?.items) ? response.result.items : [];
      const mapped = items.map((item) => {
        const id = typeof item.id === "string" ? item.id : null;
        if (!id) return null;
        const amountNet = normalizeNumber(
          item.amount_net ?? item.amountNet ?? item.amount_net_amount,
          NaN
        );
        const amountGross = normalizeNumber(
          item.amount_gross ?? item.amountGross ?? item.amount_gross_amount,
          NaN
        );
        const rateRaw = normalizeNumber(item.rate, NaN);
        const kindValue = typeof item.kind === "string" && item.kind.trim().length ? item.kind.trim() : "custom";
        const currency = typeof item.currency_code === "string" ? item.currency_code : typeof item.currencyCode === "string" ? item.currencyCode : currencyCode ?? null;
        const customFields = extractCustomFieldValues(item);
        const customFieldSetId = typeof item.custom_field_set_id === "string" ? item.custom_field_set_id : typeof item.customFieldSetId === "string" ? item.customFieldSetId : null;
        const metadata = typeof item.metadata === "object" && item.metadata ? item.metadata : null;
        return {
          id,
          label: typeof item.label === "string" ? item.label : null,
          code: typeof item.code === "string" ? item.code : null,
          kind: kindValue,
          calculatorKey: typeof item.calculator_key === "string" ? item.calculator_key : typeof item.calculatorKey === "string" ? item.calculatorKey : null,
          rate: Number.isFinite(rateRaw) ? rateRaw : null,
          amountNet: Number.isFinite(amountNet) ? amountNet : null,
          amountGross: Number.isFinite(amountGross) ? amountGross : null,
          currencyCode: currency,
          position: typeof item.position === "number" ? item.position : typeof item.position === "string" ? Number(item.position) : 0,
          customFields: Object.keys(customFields).length ? customFields : null,
          customFieldSetId,
          metadata
        };
      }).filter((entry) => Boolean(entry));
      const ordered = [...mapped].sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
      setRows(ordered);
      if (onRowsChange) onRowsChange(ordered);
    } catch (err) {
      logger.error("sales.document.adjustments.load", { err });
      setError(t("sales.documents.adjustments.errorLoad", "Failed to load adjustments."));
    } finally {
      setLoading(false);
    }
  }, [apiResourcePath, currencyCode, documentId, documentKey, onRowsChange, t]);
  React.useEffect(() => {
    void loadAdjustments();
  }, [loadAdjustments]);
  React.useEffect(
    () => subscribeSalesDocumentTotalsRefresh((detail) => {
      if (detail.documentId !== documentId) return;
      if (detail.kind && detail.kind !== kind) return;
      void loadAdjustments();
    }),
    [documentId, kind, loadAdjustments]
  );
  const resolveKindLabel = React.useCallback(
    (kindValue) => {
      const option = kindOptionMap[kindValue];
      if (option) return option.label;
      return t(`sales.documents.adjustments.kindLabels.${kindValue}`, typeof kindValue === "string" ? kindValue : String(kindValue));
    },
    [kindOptionMap, t]
  );
  const handleOpenCreate = React.useCallback(() => {
    setActiveAdjustment(null);
    setDialogOpen(true);
  }, []);
  const handleEdit = React.useCallback((row) => {
    setActiveAdjustment(row);
    setDialogOpen(true);
  }, []);
  const handleCloseDialog = React.useCallback(() => {
    setDialogOpen(false);
    setActiveAdjustment(null);
  }, []);
  React.useEffect(() => {
    if (!onActionChange) return;
    onActionChange({
      label: t("sales.documents.adjustments.add", "Add adjustment"),
      onClick: handleOpenCreate,
      disabled: false
    });
    return () => onActionChange(null);
  }, [handleOpenCreate, onActionChange, t]);
  const handleFormSubmit = React.useCallback(
    async (values) => {
      if (!resolvedOrganizationId || !resolvedTenantId) {
        throw createCrudFormError(
          t("sales.documents.adjustments.errorScope", "Organization and tenant are required.")
        );
      }
      const payload = {
        [documentKey]: String(documentId),
        organizationId: String(resolvedOrganizationId),
        tenantId: String(resolvedTenantId),
        scope: "order",
        kind: values.kind ?? "custom",
        code: values.code ?? void 0,
        label: values.label ?? void 0,
        calculatorKey: values.calculatorKey ?? void 0,
        rate: Number.isFinite(values.rate) ? values.rate : void 0,
        amountNet: Number.isFinite(values.amountNet) ? values.amountNet : void 0,
        amountGross: Number.isFinite(values.amountGross) ? values.amountGross : void 0,
        currencyCode: (values.currencyCode ?? currencyCode ?? "").toUpperCase(),
        position: Number.isFinite(values.position) ? values.position : void 0,
        customFields: values.customFields ?? void 0,
        metadata: values.metadata ?? void 0
      };
      const action = values.id ? updateCrud : createCrud;
      try {
        const result = await withScopedApiRequestHeaders(
          buildOptimisticLockHeader(documentUpdatedAt),
          () => action(
            crudResourcePath,
            values.id ? { id: values.id, ...payload } : payload,
            {
              successMessage: values.id ? t("sales.documents.adjustments.updated", "Adjustment updated.") : t("sales.documents.adjustments.created", "Adjustment added."),
              errorMessage: t("sales.documents.adjustments.errorSave", "Failed to save adjustment.")
            }
          )
        );
        if (result.ok) {
          await loadAdjustments();
          emitSalesDocumentTotalsRefresh({ documentId, kind });
          setDialogOpen(false);
          setActiveAdjustment(null);
        }
      } catch (err) {
        if (handleSectionMutationError(err, t, () => void loadAdjustments())) {
          setDialogOpen(false);
          setActiveAdjustment(null);
          return;
        }
        throw err;
      }
    },
    [
      currencyCode,
      documentId,
      documentKey,
      documentUpdatedAt,
      kind,
      loadAdjustments,
      crudResourcePath,
      resolvedOrganizationId,
      resolvedTenantId,
      t
    ]
  );
  const handleDelete = React.useCallback(
    async (row) => {
      try {
        const result = await withScopedApiRequestHeaders(
          buildOptimisticLockHeader(documentUpdatedAt),
          () => deleteCrud(crudResourcePath, {
            body: {
              id: row.id,
              [documentKey]: documentId,
              organizationId: resolvedOrganizationId ?? void 0,
              tenantId: resolvedTenantId ?? void 0
            },
            errorMessage: t("sales.documents.adjustments.errorDelete", "Failed to delete adjustment.")
          })
        );
        if (result.ok) {
          await loadAdjustments();
          emitSalesDocumentTotalsRefresh({ documentId, kind });
        }
      } catch (err) {
        if (handleSectionMutationError(err, t, () => void loadAdjustments())) return;
        logger.error("sales.document.adjustments.delete", { err });
        flash(t("sales.documents.adjustments.errorDelete", "Failed to delete adjustment."), "error");
      }
    },
    [crudResourcePath, documentId, documentKey, documentUpdatedAt, kind, loadAdjustments, resolvedOrganizationId, resolvedTenantId, t]
  );
  const columns = React.useMemo(
    () => [
      {
        id: "label",
        header: t("sales.documents.adjustments.label", "Label"),
        cell: ({ row }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
          /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: row.original.label ?? t("sales.documents.adjustments.untitled", "Untitled") }),
          row.original.code ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: row.original.code }) : null
        ] })
      },
      {
        id: "kind",
        header: t("sales.documents.adjustments.kindLabel", "Kind"),
        cell: ({ row }) => /* @__PURE__ */ jsx(Badge, { variant: "outline", children: resolveKindLabel(row.original.kind) })
      },
      {
        id: "amountNet",
        header: t("sales.documents.adjustments.amountNet", "Net amount"),
        cell: ({ row }) => /* @__PURE__ */ jsx(PriceWithCurrency, { amount: row.original.amountNet, currency: row.original.currencyCode ?? currencyCode, className: "font-mono text-sm" })
      },
      {
        id: "amountGross",
        header: t("sales.documents.adjustments.amountGross", "Gross amount"),
        cell: ({ row }) => /* @__PURE__ */ jsx(PriceWithCurrency, { amount: row.original.amountGross, currency: row.original.currencyCode ?? currencyCode, className: "font-mono text-sm" })
      },
      {
        id: "rate",
        header: t("sales.documents.adjustments.rate", "Rate"),
        cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "font-mono text-sm text-muted-foreground", children: formatPercent(row.original.rate) })
      },
      {
        id: "position",
        header: t("sales.documents.adjustments.position", "Position"),
        cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: row.original.position })
      }
    ],
    [currencyCode, resolveKindLabel, t]
  );
  const showLoadingState = loading && rows.length === 0;
  const renderRowActions = React.useCallback(
    (row) => /* @__PURE__ */ jsx(
      RowActions,
      {
        items: [
          {
            id: "edit",
            label: t("ui.actions.edit", "Edit"),
            onSelect: () => handleEdit(row)
          },
          {
            id: "delete",
            label: t("ui.actions.delete", "Delete"),
            destructive: true,
            onSelect: () => handleDelete(row)
          }
        ]
      }
    ),
    [handleDelete, handleEdit, t]
  );
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
    error ? /* @__PURE__ */ jsx(ErrorMessage, { title: t("sales.documents.adjustments.errorLoad", "Failed to load adjustments."), description: error, onRetry: () => void loadAdjustments() }) : null,
    showLoadingState ? /* @__PURE__ */ jsx(
      LoadingMessage,
      {
        label: t("sales.documents.adjustments.loading", "Loading adjustments\u2026"),
        className: "border-0 bg-transparent p-0 py-8 justify-center"
      }
    ) : /* @__PURE__ */ jsx(
      DataTable,
      {
        data: rows,
        columns,
        isLoading: loading && rows.length > 0,
        embedded: true,
        onRowClick: handleEdit,
        rowActions: renderRowActions,
        emptyState: /* @__PURE__ */ jsx(
          TabEmptyState,
          {
            title: t("sales.documents.empty.adjustments.title", "No adjustments yet."),
            description: t("sales.documents.empty.adjustments.description", "Add discounts, fees, or taxes to refine totals."),
            actionLabel: t("sales.documents.adjustments.add", "Add adjustment"),
            onAction: handleOpenCreate
          }
        )
      }
    ),
    /* @__PURE__ */ jsx(
      AdjustmentDialog,
      {
        open: dialogOpen,
        onOpenChange: (open) => {
          if (!open) {
            handleCloseDialog();
          } else {
            setDialogOpen(true);
          }
        },
        kind,
        currencyCode: currencyCode ?? null,
        kindOptions: kindOptions.length ? kindOptions : fallbackKindOptions,
        loadKindOptions,
        labels: {
          addTitle: t("sales.documents.adjustments.addTitle", "Add adjustment"),
          editTitle: t("sales.documents.adjustments.editTitle", "Edit adjustment"),
          submitCreate: t("sales.documents.adjustments.submitCreate", "Add adjustment"),
          submitUpdate: t("sales.documents.adjustments.submitUpdate", "Save changes")
        },
        initialAdjustment: activeAdjustment,
        onSubmit: handleFormSubmit
      }
    )
  ] });
}
export {
  SalesDocumentAdjustmentsSection
};
//# sourceMappingURL=AdjustmentsSection.js.map
