"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { z } from "zod";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
import { Button } from "@open-mercato/ui/primitives/button";
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue
} from "@open-mercato/ui/primitives/select";
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
import { DictionarySelectField } from "../formConfig.js";
import { createDictionarySelectLabels } from "./utils.js";
import { E } from "../../../../generated/entities.ids.generated.js";
import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
import { useCurrencyDictionary } from "./hooks/useCurrencyDictionary.js";
import { DictionaryEntrySelect } from "@open-mercato/core/modules/dictionaries/components/DictionaryEntrySelect";
import { normalizeCustomFieldSubmitValue } from "./customFieldUtils.js";
const DEAL_ENTITY_IDS = [E.customers.customer_deal];
const CURRENCY_PRIORITY = ["EUR", "USD", "GBP", "PLN"];
const PIPELINE_OPTIONS_TTL_MS = 6e4;
const PIPELINE_STAGE_OPTIONS_TTL_MS = 3e4;
let pipelineOptionsCache = null;
const pipelineStageOptionsCache = /* @__PURE__ */ new Map();
function isFreshCacheEntry(entry) {
  return Boolean(entry && entry.expiresAt > Date.now());
}
function normalizePipelineOptions(options) {
  const byId = /* @__PURE__ */ new Map();
  for (const option of options ?? []) {
    if (!option.id) continue;
    byId.set(option.id, {
      id: option.id,
      name: option.name,
      isDefault: option.isDefault === true
    });
  }
  return Array.from(byId.values());
}
function mergePipelineOptions(seed, loaded) {
  const byId = /* @__PURE__ */ new Map();
  for (const option of seed) byId.set(option.id, option);
  for (const option of loaded) byId.set(option.id, option);
  return Array.from(byId.values());
}
function normalizePipelineStageOptions(options) {
  return [...options ?? []].filter((option) => option.id).sort((left, right) => left.order - right.order);
}
async function fetchPipelineOptions() {
  if (isFreshCacheEntry(pipelineOptionsCache)) return pipelineOptionsCache.promise;
  const entry = {
    expiresAt: Date.now() + PIPELINE_OPTIONS_TTL_MS,
    promise: apiCall("/api/customers/pipelines").then((call) => call.ok && call.result?.items ? normalizePipelineOptions(call.result.items) : [])
  };
  pipelineOptionsCache = entry;
  try {
    return await entry.promise;
  } catch (error) {
    if (pipelineOptionsCache === entry) pipelineOptionsCache = null;
    throw error;
  }
}
async function fetchPipelineStageOptions(pipelineId) {
  const cached = pipelineStageOptionsCache.get(pipelineId);
  if (isFreshCacheEntry(cached)) return cached.promise;
  const entry = {
    expiresAt: Date.now() + PIPELINE_STAGE_OPTIONS_TTL_MS,
    promise: apiCall(`/api/customers/pipeline-stages?pipelineId=${encodeURIComponent(pipelineId)}`).then((call) => call.ok && call.result?.items ? normalizePipelineStageOptions(call.result.items) : [])
  };
  pipelineStageOptionsCache.set(pipelineId, entry);
  try {
    return await entry.promise;
  } catch (error) {
    if (pipelineStageOptionsCache.get(pipelineId) === entry) pipelineStageOptionsCache.delete(pipelineId);
    throw error;
  }
}
function resetDealPipelineMetadataCacheForTests() {
  pipelineOptionsCache = null;
  pipelineStageOptionsCache.clear();
}
const schema = z.object({
  title: z.string().trim().min(1, "customers.people.detail.deals.titleRequired").max(200, "customers.people.detail.deals.titleTooLong"),
  status: z.string().trim().max(50, "customers.people.detail.deals.statusTooLong").optional(),
  pipelineStage: z.string().trim().max(100, "customers.people.detail.deals.pipelineTooLong").optional(),
  pipelineId: z.preprocess(
    (v) => typeof v === "string" && !v.trim() ? void 0 : v,
    z.string().uuid("customers.people.detail.deals.pipelineIdInvalid").optional()
  ),
  pipelineStageId: z.preprocess(
    (v) => typeof v === "string" && !v.trim() ? void 0 : v,
    z.string().uuid("customers.people.detail.deals.pipelineStageIdInvalid").optional()
  ),
  valueAmount: z.preprocess((value) => {
    if (value === "" || value === null || value === void 0) return void 0;
    if (typeof value === "number") return value;
    if (typeof value === "string") {
      const trimmed = value.trim();
      if (!trimmed) return void 0;
      const parsed = Number(trimmed);
      if (Number.isNaN(parsed)) return value;
      return parsed;
    }
    return value;
  }, z.number().min(0, "customers.people.detail.deals.valueInvalid").optional()).optional(),
  valueCurrency: z.string().transform((value) => value.trim().toUpperCase()).refine(
    (value) => !value || /^[A-Z]{3}$/.test(value),
    "customers.people.detail.deals.currencyInvalid"
  ).optional(),
  probability: z.preprocess((value) => {
    if (value === "" || value === null || value === void 0) return void 0;
    if (typeof value === "number") return value;
    if (typeof value === "string") {
      const trimmed = value.trim();
      if (!trimmed) return void 0;
      const parsed = Number(trimmed);
      if (Number.isNaN(parsed)) return value;
      return parsed;
    }
    return value;
  }, z.number().min(0, "customers.people.detail.deals.probabilityInvalid").max(100, "customers.people.detail.deals.probabilityInvalid").optional()).optional(),
  expectedCloseAt: z.string().transform((value) => value.trim()).refine(
    (value) => {
      if (!value) return true;
      const parsed = new Date(value);
      return !Number.isNaN(parsed.getTime());
    },
    "customers.people.detail.deals.expectedCloseInvalid"
  ).optional(),
  description: z.string().max(4e3, "customers.people.detail.deals.descriptionTooLong").optional(),
  personIds: z.array(z.string().trim().min(1)).optional(),
  companyIds: z.array(z.string().trim().min(1)).optional()
}).passthrough();
const dealFormSchema = schema;
import { toDateInputValue as toDateInputValueOrNull } from "@open-mercato/shared/lib/date/format";
function toDateInputValue(value) {
  return toDateInputValueOrNull(value) ?? "";
}
function normalizeCurrency(value) {
  if (!value) return "";
  return value.trim().slice(0, 3).toUpperCase();
}
function sanitizeIdList(input) {
  if (!Array.isArray(input)) return [];
  const set = /* @__PURE__ */ new Set();
  input.forEach((candidate) => {
    if (typeof candidate !== "string") return;
    const trimmed = candidate.trim();
    if (!trimmed.length) return;
    set.add(trimmed);
  });
  return Array.from(set);
}
function extractPersonOption(record) {
  const id = typeof record.id === "string" ? record.id : null;
  if (!id) return null;
  const displayName = typeof record.displayName === "string" && record.displayName.trim().length ? record.displayName.trim() : typeof record.display_name === "string" && record.display_name.trim().length ? record.display_name.trim() : null;
  const email = typeof record.primaryEmail === "string" && record.primaryEmail.trim().length ? record.primaryEmail.trim() : typeof record.primary_email === "string" && record.primary_email.trim().length ? record.primary_email.trim() : null;
  const label = displayName ?? email ?? id;
  const subtitle = email && email !== label ? email : null;
  return { id, label, subtitle };
}
function extractCompanyOption(record) {
  const id = typeof record.id === "string" ? record.id : null;
  if (!id) return null;
  const displayName = typeof record.displayName === "string" && record.displayName.trim().length ? record.displayName.trim() : typeof record.display_name === "string" && record.display_name.trim().length ? record.display_name.trim() : null;
  const domain = typeof record.domain === "string" && record.domain.trim().length ? record.domain.trim() : typeof record.websiteUrl === "string" && record.websiteUrl.trim().length ? record.websiteUrl.trim() : typeof record.website_url === "string" && record.website_url.trim().length ? record.website_url.trim() : null;
  const label = displayName ?? domain ?? id;
  const subtitle = domain && domain !== label ? domain : null;
  return { id, label, subtitle };
}
function EntityMultiSelect({
  value,
  onChange,
  initialOptions = [],
  placeholder,
  emptyLabel,
  loadingLabel,
  noResultsLabel,
  removeLabel,
  errorLabel,
  search,
  fetchByIds,
  disabled = false,
  autoFocus = false
}) {
  const [input, setInput] = React.useState("");
  const [suggestions, setSuggestions] = React.useState([]);
  const [cache, setCache] = React.useState(() => /* @__PURE__ */ new Map());
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);
  const normalizedValue = React.useMemo(() => sanitizeIdList(value), [value]);
  React.useEffect(() => {
    if (!initialOptions.length) return;
    setCache((prev) => {
      const next = new Map(prev);
      initialOptions.forEach((option) => {
        if (option?.id) next.set(option.id, option);
      });
      return next;
    });
  }, [initialOptions]);
  React.useEffect(() => {
    if (!normalizedValue.length) return;
    const missing = normalizedValue.filter((id) => !cache.has(id));
    if (!missing.length) return;
    let cancelled = false;
    (async () => {
      try {
        const entries = await fetchByIds(missing);
        if (cancelled) return;
        setCache((prev) => {
          const next = new Map(prev);
          entries.forEach((entry) => {
            if (entry?.id) next.set(entry.id, entry);
          });
          return next;
        });
      } catch {
        if (!cancelled) setError(errorLabel);
      }
    })().catch(() => {
    });
    return () => {
      cancelled = true;
    };
  }, [cache, errorLabel, fetchByIds, normalizedValue]);
  React.useEffect(() => {
    if (disabled) {
      setLoading(false);
      return;
    }
    let cancelled = false;
    const handler = window.setTimeout(async () => {
      setLoading(true);
      try {
        const results = await search(input.trim());
        if (cancelled) return;
        setSuggestions(results);
        setCache((prev) => {
          const next = new Map(prev);
          results.forEach((entry) => {
            if (entry?.id) next.set(entry.id, entry);
          });
          return next;
        });
        setError(null);
      } catch {
        if (!cancelled) {
          setError(errorLabel);
          setSuggestions([]);
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    }, 200);
    return () => {
      cancelled = true;
      window.clearTimeout(handler);
    };
  }, [disabled, errorLabel, input, search]);
  const filteredSuggestions = React.useMemo(
    () => suggestions.filter((option) => !normalizedValue.includes(option.id)),
    [normalizedValue, suggestions]
  );
  const selectedOptions = React.useMemo(
    () => normalizedValue.map((id) => cache.get(id) ?? { id, label: id }),
    [cache, normalizedValue]
  );
  const addOption = React.useCallback(
    (option) => {
      if (!option?.id) return;
      if (normalizedValue.includes(option.id)) return;
      const next = [...normalizedValue, option.id];
      onChange(next);
      setCache((prev) => {
        const nextCache = new Map(prev);
        nextCache.set(option.id, option);
        return nextCache;
      });
      setInput("");
      setSuggestions([]);
    },
    [normalizedValue, onChange]
  );
  const removeOption = React.useCallback(
    (id) => {
      const next = normalizedValue.filter((candidate) => candidate !== id);
      onChange(next);
    },
    [normalizedValue, onChange]
  );
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
    /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 rounded border px-2 py-1", children: [
      selectedOptions.map((option) => /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded bg-muted px-2 py-0.5 text-xs", children: [
        option.label,
        /* @__PURE__ */ jsx(
          IconButton,
          {
            variant: "ghost",
            size: "xs",
            className: "opacity-60 hover:opacity-100",
            onClick: () => removeOption(option.id),
            "aria-label": `${removeLabel} ${option.label}`,
            disabled,
            children: "\xD7"
          }
        )
      ] }, option.id)),
      /* @__PURE__ */ jsx(
        "input",
        {
          type: "text",
          className: "flex-1 min-w-[160px] border-0 bg-transparent py-1 text-sm outline-none",
          value: input,
          placeholder,
          onChange: (event) => setInput(event.target.value),
          onKeyDown: (event) => {
            if (event.key === "Enter") {
              event.preventDefault();
              const nextOption = filteredSuggestions[0];
              if (nextOption) addOption(nextOption);
            } else if (event.key === "Backspace" && !input.length && normalizedValue.length) {
              removeOption(normalizedValue[normalizedValue.length - 1]);
            }
          },
          disabled,
          autoFocus,
          "data-crud-focus-target": ""
        }
      )
    ] }),
    loading ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: loadingLabel }) : null,
    !loading && filteredSuggestions.length ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: filteredSuggestions.slice(0, 10).map((option) => /* @__PURE__ */ jsx(
      Button,
      {
        variant: "outline",
        size: "sm",
        className: "h-auto px-2 py-1 text-xs font-normal",
        onMouseDown: (event) => event.preventDefault(),
        onClick: () => addOption(option),
        disabled,
        "aria-label": option.label,
        children: /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-start", children: [
          /* @__PURE__ */ jsx("span", { children: option.label }),
          option.subtitle ? /* @__PURE__ */ jsx("span", { className: "text-overline text-muted-foreground", children: option.subtitle }) : null
        ] })
      },
      option.id
    )) }) : null,
    !loading && !filteredSuggestions.length && input.trim().length ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: noResultsLabel }) : null,
    error ? /* @__PURE__ */ jsx("div", { className: "text-xs text-status-error-text", children: error }) : null,
    !normalizedValue.length && !input.trim().length ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: emptyLabel }) : null
  ] });
}
function useDealAssociationLookups(options) {
  const searchPeoplePage = React.useCallback(async (query, page = 1) => {
    const params = new URLSearchParams({
      page: String(page),
      pageSize: "20",
      sortField: "name",
      sortDir: "asc"
    });
    if (query.trim().length) params.set("search", query.trim());
    if (options?.excludeLinkedDealId) params.set("excludeLinkedDealId", options.excludeLinkedDealId);
    const call = await apiCall(`/api/customers/people?${params.toString()}`);
    if (!call.ok) {
      throw new Error(typeof call.result?.error === "string" ? String(call.result?.error) : "Failed to search people");
    }
    const payload = call.result ?? {};
    const items = Array.isArray(payload.items) ? payload.items : [];
    return {
      items: items.map((item) => item && typeof item === "object" ? extractPersonOption(item) : null).filter((entry) => entry !== null),
      totalPages: typeof payload.totalPages === "number" ? payload.totalPages : 1
    };
  }, [options?.excludeLinkedDealId]);
  const searchPeople = React.useCallback(async (query) => {
    const result = await searchPeoplePage(query, 1);
    return result.items;
  }, [searchPeoplePage]);
  const fetchPeopleByIds = React.useCallback(async (ids) => {
    const unique = sanitizeIdList(ids);
    if (!unique.length) return [];
    try {
      const params = new URLSearchParams({
        ids: unique.join(","),
        pageSize: String(Math.max(unique.length, 1))
      });
      const call = await apiCall(`/api/customers/people?${params.toString()}`);
      if (!call.ok) throw new Error();
      const payload = call.result ?? {};
      const items = Array.isArray(payload.items) ? payload.items : [];
      const optionMap = /* @__PURE__ */ new Map();
      items.forEach((item) => {
        if (!item || typeof item !== "object") return;
        const option = extractPersonOption(item);
        if (option?.id) optionMap.set(option.id, option);
      });
      return unique.map((id) => optionMap.get(id) ?? { id, label: id });
    } catch {
      return unique.map((id) => ({ id, label: id }));
    }
  }, []);
  const searchCompaniesPage = React.useCallback(async (query, page = 1) => {
    const params = new URLSearchParams({
      page: String(page),
      pageSize: "20",
      sortField: "name",
      sortDir: "asc"
    });
    if (query.trim().length) params.set("search", query.trim());
    if (options?.excludeLinkedDealId) params.set("excludeLinkedDealId", options.excludeLinkedDealId);
    const call = await apiCall(`/api/customers/companies?${params.toString()}`);
    if (!call.ok) {
      throw new Error(typeof call.result?.error === "string" ? String(call.result?.error) : "Failed to search companies");
    }
    const payload = call.result ?? {};
    const items = Array.isArray(payload.items) ? payload.items : [];
    return {
      items: items.map((item) => item && typeof item === "object" ? extractCompanyOption(item) : null).filter((entry) => entry !== null),
      totalPages: typeof payload.totalPages === "number" ? payload.totalPages : 1
    };
  }, [options?.excludeLinkedDealId]);
  const searchCompanies = React.useCallback(async (query) => {
    const result = await searchCompaniesPage(query, 1);
    return result.items;
  }, [searchCompaniesPage]);
  const fetchCompaniesByIds = React.useCallback(async (ids) => {
    const unique = sanitizeIdList(ids);
    if (!unique.length) return [];
    try {
      const params = new URLSearchParams({
        ids: unique.join(","),
        pageSize: String(Math.max(unique.length, 1))
      });
      const call = await apiCall(`/api/customers/companies?${params.toString()}`);
      if (!call.ok) throw new Error();
      const payload = call.result ?? {};
      const items = Array.isArray(payload.items) ? payload.items : [];
      const optionMap = /* @__PURE__ */ new Map();
      items.forEach((item) => {
        if (!item || typeof item !== "object") return;
        const option = extractCompanyOption(item);
        if (option?.id) optionMap.set(option.id, option);
      });
      return unique.map((id) => optionMap.get(id) ?? { id, label: id });
    } catch {
      return unique.map((id) => ({ id, label: id }));
    }
  }, []);
  return {
    searchPeople,
    searchPeoplePage,
    fetchPeopleByIds,
    searchCompanies,
    searchCompaniesPage,
    fetchCompaniesByIds
  };
}
function DealPeopleSelector({
  value,
  onChange,
  options = [],
  disabled = false,
  autoFocus = false
}) {
  const t = useT();
  const { searchPeople, fetchPeopleByIds } = useDealAssociationLookups();
  return /* @__PURE__ */ jsx(
    EntityMultiSelect,
    {
      value,
      onChange,
      initialOptions: options,
      placeholder: t("customers.deals.form.people.searchPlaceholder", "Search people\u2026"),
      emptyLabel: t("customers.deals.form.people.empty", "No people linked yet."),
      loadingLabel: t("customers.deals.form.people.loading", "Searching people\u2026"),
      noResultsLabel: t("customers.deals.form.people.noResults", "No people match your search."),
      removeLabel: t("customers.deals.form.assignees.remove", "Remove"),
      errorLabel: t("customers.deals.form.people.error", "Failed to load people."),
      search: searchPeople,
      fetchByIds: fetchPeopleByIds,
      disabled,
      autoFocus
    }
  );
}
function DealCompaniesSelector({
  value,
  onChange,
  options = [],
  disabled = false
}) {
  const t = useT();
  const { searchCompanies, fetchCompaniesByIds } = useDealAssociationLookups();
  return /* @__PURE__ */ jsx(
    EntityMultiSelect,
    {
      value,
      onChange,
      initialOptions: options,
      placeholder: t("customers.deals.form.companies.searchPlaceholder", "Search companies\u2026"),
      emptyLabel: t("customers.deals.form.companies.empty", "No companies linked yet."),
      loadingLabel: t("customers.deals.form.companies.loading", "Searching companies\u2026"),
      noResultsLabel: t("customers.deals.form.companies.noResults", "No companies match your search."),
      removeLabel: t("customers.deals.form.assignees.remove", "Remove"),
      errorLabel: t("customers.deals.form.companies.error", "Failed to load companies."),
      search: searchCompanies,
      fetchByIds: fetchCompaniesByIds,
      disabled
    }
  );
}
function DealForm({
  mode,
  initialValues,
  onSubmit,
  onCancel,
  onDelete,
  submitLabel,
  cancelLabel,
  isSubmitting = false,
  embedded = true,
  trackDirtyWhenEmbedded = false,
  title,
  backHref,
  hideFooterActions = false,
  onDirtyChange,
  collapsibleGroups,
  sortableGroups,
  singleColumnGroups = false,
  showAssociationsGroup = true,
  showVersionHistory = true,
  showCancelAction = true,
  initialPipelineOptions,
  initialPipelineStageOptions,
  injectionSpotId,
  optimisticLockUpdatedAt
}) {
  const t = useT();
  const [pending, setPending] = React.useState(false);
  const {
    data: currencyDictionaryData,
    error: currencyDictionaryErrorRaw,
    isLoading: currencyDictionaryLoading,
    refetch: refetchCurrencyDictionary
  } = useCurrencyDictionary();
  const currencyDictionaryError = currencyDictionaryErrorRaw ? currencyDictionaryErrorRaw instanceof Error ? currencyDictionaryErrorRaw.message : String(currencyDictionaryErrorRaw) : null;
  const translate = React.useCallback(
    (key, fallback) => {
      const value = t(key);
      return value === key ? fallback : value;
    },
    [t]
  );
  const dictionaryLabels = React.useMemo(() => ({
    status: createDictionarySelectLabels("deal-statuses", translate)
  }), [translate]);
  const resolvedCurrencyError = React.useMemo(() => {
    if (currencyDictionaryError) return currencyDictionaryError;
    if (!currencyDictionaryLoading && !currencyDictionaryData) {
      return t("customers.deals.form.currency.missing", "Currency dictionary is not configured yet.");
    }
    return null;
  }, [currencyDictionaryData, currencyDictionaryError, currencyDictionaryLoading, t]);
  const fetchCurrencyOptions = React.useCallback(async () => {
    let payload = currencyDictionaryData ?? null;
    if (!payload) {
      try {
        payload = await refetchCurrencyDictionary();
      } catch (err) {
        const message = err instanceof Error ? err.message : String(err ?? "");
        throw new Error(message || t("customers.deals.form.currency.error", "Failed to load currency dictionary."));
      }
    }
    if (!payload) {
      throw new Error(t("customers.deals.form.currency.missing", "Currency dictionary is not configured yet."));
    }
    const priorityOrder = /* @__PURE__ */ new Map();
    CURRENCY_PRIORITY.forEach((code, index) => priorityOrder.set(code, index));
    const prioritized = [];
    const remainder = [];
    payload.entries.forEach((entry) => {
      const value = entry.value.toUpperCase();
      const label = entry.label && entry.label.length ? `${value} \u2013 ${entry.label}` : value;
      const option = { value, label, color: null, icon: null };
      if (priorityOrder.has(value)) prioritized.push(option);
      else remainder.push(option);
    });
    prioritized.sort((a, b) => priorityOrder.get(a.value) - priorityOrder.get(b.value));
    remainder.sort((a, b) => a.label.localeCompare(b.label, void 0, { sensitivity: "base" }));
    return [...prioritized, ...remainder];
  }, [currencyDictionaryData, refetchCurrencyDictionary, t]);
  const currencyDictionaryLabels = React.useMemo(() => ({
    placeholder: t("customers.deals.form.currency.placeholder", "Select currency\u2026"),
    addLabel: t("customers.deals.form.currency.add", "Add currency"),
    dialogTitle: t("customers.deals.form.currency.dialogTitle", "Add currency"),
    valueLabel: t("customers.deals.form.currency.valueLabel", "Currency code"),
    valuePlaceholder: t("customers.deals.form.currency.valuePlaceholder", "e.g. USD"),
    labelLabel: t("customers.deals.form.currency.labelLabel", "Label"),
    labelPlaceholder: t("customers.deals.form.currency.labelPlaceholder", "Display name shown in UI"),
    emptyError: t("customers.deals.form.currency.error.required", "Currency code is required."),
    cancelLabel: t("customers.deals.form.currency.cancel", "Cancel"),
    saveLabel: t("customers.deals.form.currency.save", "Save"),
    errorLoad: t("customers.deals.form.currency.error", "Failed to load currency dictionary."),
    errorSave: t("customers.deals.form.currency.error", "Failed to load currency dictionary."),
    loadingLabel: t("customers.deals.form.currency.loading", "Loading currencies\u2026"),
    manageTitle: t("customers.deals.form.currency.manage", "Manage currency dictionary")
  }), [t]);
  const { searchPeople, fetchPeopleByIds, searchCompanies, fetchCompaniesByIds } = useDealAssociationLookups();
  const disabled = pending || isSubmitting;
  const canDelete = mode === "edit" && typeof onDelete === "function";
  const mountedRef = React.useRef(false);
  const seedPipelineOptions = React.useMemo(
    () => normalizePipelineOptions(initialPipelineOptions),
    [initialPipelineOptions]
  );
  const seedPipelineStageOptions = React.useMemo(
    () => Array.isArray(initialPipelineStageOptions) ? normalizePipelineStageOptions(initialPipelineStageOptions) : null,
    [initialPipelineStageOptions]
  );
  const [pipelines, setPipelines] = React.useState(() => seedPipelineOptions);
  const [pipelineStages, setPipelineStages] = React.useState(() => seedPipelineStageOptions ?? []);
  React.useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
    };
  }, []);
  const loadStagesForPipeline = React.useCallback(async (pipelineId) => {
    if (!pipelineId) {
      if (mountedRef.current) setPipelineStages([]);
      return;
    }
    try {
      const stages = await fetchPipelineStageOptions(pipelineId);
      if (mountedRef.current) setPipelineStages(stages);
    } catch {
      if (mountedRef.current) setPipelineStages([]);
    }
  }, []);
  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const loaded = await fetchPipelineOptions();
        if (cancelled || !mountedRef.current) return;
        setPipelines(mergePipelineOptions(seedPipelineOptions, loaded));
      } catch {
        if (!cancelled && mountedRef.current && seedPipelineOptions.length > 0) {
          setPipelines(seedPipelineOptions);
        }
      }
    })().catch(() => {
    });
    return () => {
      cancelled = true;
    };
  }, [seedPipelineOptions]);
  React.useEffect(() => {
    const pid = initialValues?.pipelineId;
    if (typeof pid === "string" && pid.length) {
      if (seedPipelineStageOptions) {
        setPipelineStages(seedPipelineStageOptions);
        return;
      }
      loadStagesForPipeline(pid).catch(() => {
      });
    } else {
      setPipelineStages([]);
    }
  }, [initialValues?.pipelineId, loadStagesForPipeline, seedPipelineStageOptions]);
  const baseFields = React.useMemo(() => [
    {
      id: "title",
      label: t("customers.people.detail.deals.fields.title", "Title"),
      type: "text",
      required: true
    },
    {
      id: "status",
      label: t("customers.people.detail.deals.fields.status", "Status"),
      type: "custom",
      layout: "half",
      component: ({ value, setValue }) => /* @__PURE__ */ jsx(
        DictionarySelectField,
        {
          kind: "deal-statuses",
          value: typeof value === "string" ? value : void 0,
          onChange: (next) => setValue(next ?? ""),
          labels: dictionaryLabels.status,
          selectClassName: "w-full"
        }
      )
    },
    {
      id: "pipelineId",
      label: t("customers.people.detail.deals.fields.pipeline", "Pipeline"),
      type: "custom",
      layout: "half",
      component: ({ value, setValue, setFormValue }) => /* @__PURE__ */ jsxs(
        Select,
        {
          value: typeof value === "string" && value ? value : void 0,
          onValueChange: (next) => {
            setValue(next ?? "");
            setFormValue?.("pipelineStageId", "");
            loadStagesForPipeline(next ?? "").catch(() => {
            });
          },
          disabled,
          children: [
            /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("customers.deals.form.pipeline.placeholder", "Select pipeline\u2026") }) }),
            /* @__PURE__ */ jsx(SelectContent, { children: pipelines.map((p) => /* @__PURE__ */ jsx(SelectItem, { value: p.id, children: p.name }, p.id)) })
          ]
        }
      )
    },
    {
      id: "pipelineStageId",
      label: t("customers.people.detail.deals.fields.pipelineStage", "Pipeline stage"),
      type: "custom",
      layout: "half",
      component: ({ value, setValue }) => /* @__PURE__ */ jsxs(
        Select,
        {
          value: typeof value === "string" && value ? value : void 0,
          onValueChange: (next) => setValue(next ?? ""),
          disabled: disabled || !pipelineStages.length,
          children: [
            /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("customers.deals.form.pipelineStage.placeholder", "Select stage\u2026") }) }),
            /* @__PURE__ */ jsx(SelectContent, { children: pipelineStages.map((s) => /* @__PURE__ */ jsx(SelectItem, { value: s.id, children: s.label }, s.id)) })
          ]
        }
      )
    },
    {
      id: "valueAmount",
      label: t("customers.people.detail.deals.fields.valueAmount", "Amount"),
      type: "number",
      layout: "half"
    },
    {
      id: "valueCurrency",
      label: t("customers.people.detail.deals.fields.valueCurrency", "Currency"),
      type: "custom",
      layout: "half",
      component: ({ value, setValue }) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
        /* @__PURE__ */ jsx(
          DictionaryEntrySelect,
          {
            value: typeof value === "string" ? value : void 0,
            onChange: (next) => setValue(next ?? ""),
            fetchOptions: fetchCurrencyOptions,
            labels: currencyDictionaryLabels,
            manageHref: "/backend/config/dictionaries?key=currency",
            allowInlineCreate: false,
            allowAppearance: false,
            selectClassName: "w-full",
            sortOptions: "none",
            disabled,
            showLabelInput: false
          }
        ),
        resolvedCurrencyError ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: resolvedCurrencyError }) : null
      ] })
    },
    {
      id: "probability",
      label: t("customers.people.detail.deals.fields.probability", "Probability (%)"),
      type: "number",
      layout: "half"
    },
    {
      id: "expectedCloseAt",
      label: t("customers.people.detail.deals.fields.expectedCloseAt", "Expected close"),
      type: "date",
      layout: "half"
    },
    {
      id: "description",
      label: t("customers.people.detail.deals.fields.description", "Description"),
      type: "textarea"
    },
    {
      id: "personIds",
      label: t("customers.people.detail.deals.fields.people", "People"),
      type: "custom",
      component: ({ value, setValue, autoFocus }) => /* @__PURE__ */ jsx(
        EntityMultiSelect,
        {
          value: Array.isArray(value) ? value : [],
          onChange: (next) => setValue(next),
          placeholder: t("customers.deals.form.people.searchPlaceholder", "Search people\u2026"),
          emptyLabel: t("customers.deals.form.people.empty", "No people linked yet."),
          loadingLabel: t("customers.deals.form.people.loading", "Searching people\u2026"),
          noResultsLabel: t("customers.deals.form.people.noResults", "No people match your search."),
          removeLabel: t("customers.deals.form.assignees.remove", "Remove"),
          errorLabel: t("customers.deals.form.people.error", "Failed to load people."),
          search: searchPeople,
          fetchByIds: fetchPeopleByIds,
          disabled,
          autoFocus
        }
      )
    },
    {
      id: "companyIds",
      label: t("customers.people.detail.deals.fields.companies", "Companies"),
      type: "custom",
      component: ({ value, setValue }) => /* @__PURE__ */ jsx(
        EntityMultiSelect,
        {
          value: Array.isArray(value) ? value : [],
          onChange: (next) => setValue(next),
          placeholder: t("customers.deals.form.companies.searchPlaceholder", "Search companies\u2026"),
          emptyLabel: t("customers.deals.form.companies.empty", "No companies linked yet."),
          loadingLabel: t("customers.deals.form.companies.loading", "Searching companies\u2026"),
          noResultsLabel: t("customers.deals.form.companies.noResults", "No companies match your search."),
          removeLabel: t("customers.deals.form.assignees.remove", "Remove"),
          errorLabel: t("customers.deals.form.companies.error", "Failed to load companies."),
          search: searchCompanies,
          fetchByIds: fetchCompaniesByIds,
          disabled
        }
      )
    }
  ], [currencyDictionaryLabels, fetchCurrencyOptions, resolvedCurrencyError, pipelines, pipelineStages, loadStagesForPipeline, dictionaryLabels.status, disabled, fetchCompaniesByIds, fetchPeopleByIds, searchCompanies, searchPeople, t]);
  const groups = React.useMemo(() => {
    const nextGroups = [
      {
        id: "details",
        title: t("customers.people.detail.deals.form.details", "Deal details"),
        column: 1,
        fields: ["title", "status", "pipelineId", "pipelineStageId", "valueAmount", "valueCurrency", "probability", "expectedCloseAt", "description"]
      },
      ...showAssociationsGroup ? [{
        id: "associations",
        title: t("customers.people.detail.deals.form.associations", "Associations"),
        column: 1,
        fields: ["personIds", "companyIds"]
      }] : [],
      {
        id: "custom",
        title: t("customers.people.detail.deals.form.customFields", "Custom fields"),
        column: 2,
        kind: "customFields"
      }
    ];
    return nextGroups.map((group) => singleColumnGroups ? { ...group, column: 1 } : group);
  }, [showAssociationsGroup, singleColumnGroups, t]);
  const embeddedInitialValues = React.useMemo(() => {
    const normalizeNumber = (value) => {
      if (typeof value === "number" && Number.isFinite(value)) return value;
      if (typeof value === "string") {
        const parsed = Number(value);
        return Number.isNaN(parsed) ? null : parsed;
      }
      return null;
    };
    const resolveIdsFromSource = (source) => {
      if (Array.isArray(source)) {
        return sanitizeIdList(
          source.map((entry) => {
            if (typeof entry === "string") return entry;
            if (entry && typeof entry === "object" && "id" in entry) {
              const candidate = entry.id;
              if (typeof candidate === "string") return candidate;
            }
            return null;
          })
        );
      }
      return [];
    };
    return {
      id: typeof initialValues?.id === "string" ? initialValues.id : void 0,
      title: initialValues?.title ?? "",
      status: initialValues?.status ?? "",
      pipelineStage: initialValues?.pipelineStage ?? "",
      pipelineId: initialValues?.pipelineId ?? (typeof initialValues?.pipeline_id === "string" ? initialValues.pipeline_id : ""),
      pipelineStageId: initialValues?.pipelineStageId ?? (typeof initialValues?.pipeline_stage_id === "string" ? initialValues.pipeline_stage_id : ""),
      valueAmount: normalizeNumber(initialValues?.valueAmount ?? null),
      valueCurrency: normalizeCurrency(initialValues?.valueCurrency ?? null),
      probability: normalizeNumber(initialValues?.probability ?? null),
      expectedCloseAt: toDateInputValue(initialValues?.expectedCloseAt ?? null),
      description: initialValues?.description ?? "",
      personIds: sanitizeIdList(initialValues?.personIds ?? resolveIdsFromSource(initialValues?.people)),
      companyIds: sanitizeIdList(initialValues?.companyIds ?? resolveIdsFromSource(initialValues?.companies)),
      ...Object.fromEntries(
        Object.entries(initialValues ?? {}).filter(([key]) => key.startsWith("cf_")).map(([key, value]) => [key, value])
      )
    };
  }, [initialValues]);
  const handleSubmit = React.useCallback(
    async (values) => {
      if (pending || isSubmitting) return;
      setPending(true);
      try {
        const parsed = schema.safeParse(values);
        if (!parsed.success) {
          throw buildDealValidationError(parsed.error.issues, t);
        }
        const expectedCloseAt = parsed.data.expectedCloseAt && parsed.data.expectedCloseAt.length ? new Date(parsed.data.expectedCloseAt).toISOString() : void 0;
        const personIds = sanitizeIdList(parsed.data.personIds);
        const companyIds = sanitizeIdList(parsed.data.companyIds);
        const base = {
          title: parsed.data.title,
          status: parsed.data.status || void 0,
          pipelineStage: parsed.data.pipelineStage || void 0,
          pipelineId: parsed.data.pipelineId || void 0,
          pipelineStageId: parsed.data.pipelineStageId || void 0,
          valueAmount: typeof parsed.data.valueAmount === "number" ? parsed.data.valueAmount : void 0,
          valueCurrency: parsed.data.valueCurrency || void 0,
          probability: typeof parsed.data.probability === "number" ? parsed.data.probability : void 0,
          expectedCloseAt,
          description: parsed.data.description && parsed.data.description.length ? parsed.data.description : void 0,
          personIds,
          companyIds
        };
        const customEntries = collectCustomFieldValues(values, {
          transform: (value) => normalizeCustomFieldSubmitValue(value)
        });
        await onSubmit({ base, custom: customEntries });
      } finally {
        setPending(false);
      }
    },
    [isSubmitting, onSubmit, pending, t]
  );
  return /* @__PURE__ */ jsx(
    CrudForm,
    {
      embedded,
      trackDirtyWhenEmbedded,
      title,
      backHref,
      hideFooterActions,
      onDirtyChange,
      injectionSpotId,
      optimisticLockUpdatedAt,
      collapsibleGroups,
      sortableGroups,
      versionHistory: showVersionHistory && mode === "edit" && initialValues?.id ? { resourceKind: "customers.deal", resourceId: String(initialValues.id) } : void 0,
      schema,
      fields: baseFields,
      groups,
      entityIds: DEAL_ENTITY_IDS,
      initialValues: embeddedInitialValues,
      onSubmit: handleSubmit,
      onDelete: canDelete ? onDelete : void 0,
      deleteVisible: canDelete,
      submitLabel: submitLabel ?? (mode === "edit" ? t("customers.people.detail.deals.update", "Update deal (\u2318/Ctrl + Enter)") : t("customers.people.detail.deals.save", "Save deal (\u2318/Ctrl + Enter)")),
      extraActions: showCancelAction ? /* @__PURE__ */ jsx(
        Button,
        {
          type: "button",
          variant: "outline",
          onClick: onCancel,
          disabled: pending || isSubmitting,
          children: cancelLabel ?? t("customers.people.detail.deals.cancel", "Cancel")
        }
      ) : void 0
    }
  );
}
function buildDealValidationError(issues, t) {
  const issue = issues[0];
  const message = typeof issue?.message === "string" ? issue.message : t("customers.people.detail.deals.error", "Failed to save deal.");
  const firstPath = Array.isArray(issue?.path) ? issue?.path?.[0] : void 0;
  const field = typeof firstPath === "string" ? firstPath : void 0;
  throw createCrudFormError(message, field ? { [field]: message } : void 0);
}
var DealForm_default = DealForm;
export {
  DealCompaniesSelector,
  DealForm,
  DealPeopleSelector,
  buildDealValidationError,
  dealFormSchema,
  DealForm_default as default,
  resetDealPipelineMetadataCacheForTests,
  useDealAssociationLookups
};
//# sourceMappingURL=DealForm.js.map
