"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import {
  CalendarDays,
  ChevronsLeft,
  ChevronsRight,
  ChevronDown,
  ChevronUp,
  Check,
  GripVertical,
  Hash,
  Info,
  Plus,
  Radio,
  RefreshCw,
  Save,
  Search,
  Tag,
  Thermometer,
  Trash2,
  Users,
  X
} from "lucide-react";
import {
  DndContext,
  closestCenter,
  PointerSensor,
  KeyboardSensor,
  useSensor,
  useSensors
} from "@dnd-kit/core";
import {
  SortableContext,
  verticalListSortingStrategy,
  useSortable,
  arrayMove
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { apiCallOrThrow, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
import { Badge } from "@open-mercato/ui/primitives/badge";
import { Button } from "@open-mercato/ui/primitives/button";
import { ColorPicker } from "@open-mercato/ui/primitives/color-picker";
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
import { ScrollArea } from "@open-mercato/ui/primitives/scroll-area";
import {
  Dialog,
  DialogContent,
  DialogTitle
} from "@open-mercato/ui/primitives/dialog";
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("customers");
const BUILTIN_CATEGORIES = [
  {
    kind: "statuses",
    icon: Tag,
    shortLabelKey: "customers.personTags.category.statuses",
    shortLabelFallback: "Status",
    descriptionKey: "customers.tags.manage.description.customers.status",
    descriptionFallback: "Single-select values visible on the hero area of person, company, and deal cards.",
    badges: ["system", "required"],
    noteTitleKey: "customers.tags.manage.noteTitle.customers.status",
    noteTitleFallback: "System category",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.status",
    noteDescriptionFallback: "Status is required on customer cards. Existing rows can be edited, but this category should remain available tenant-wide."
  },
  {
    kind: "lifecycle-stages",
    icon: RefreshCw,
    shortLabelKey: "customers.personTags.category.lifecycle-stages",
    shortLabelFallback: "Lifecycle",
    descriptionKey: "customers.tags.manage.description.customers.lifecycle_stage",
    descriptionFallback: "Pipeline-aligned lifecycle values shared across CRM detail pages.",
    badges: ["system"],
    noteTitleKey: "customers.tags.manage.noteTitle.customers.lifecycle_stage",
    noteTitleFallback: "Shared lifecycle values",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.lifecycle_stage",
    noteDescriptionFallback: "Use lifecycle stages to keep person and company headers visually consistent across CRM detail views."
  },
  {
    kind: "sources",
    icon: Radio,
    shortLabelKey: "customers.personTags.category.sources",
    shortLabelFallback: "Source",
    descriptionKey: "customers.tags.manage.description.customers.source",
    descriptionFallback: "Acquisition source labels used in Zone 1 forms and CRM summary badges.",
    badges: ["system"],
    noteTitleKey: "customers.tags.manage.noteTitle.customers.source",
    noteTitleFallback: "Source dictionary",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.source",
    noteDescriptionFallback: "These values are reused by customer forms and reporting filters."
  },
  {
    kind: "temperature",
    icon: Thermometer,
    shortLabelKey: "customers.personTags.category.temperature",
    shortLabelFallback: "Temperature",
    descriptionKey: "customers.tags.manage.description.customers.temperature",
    descriptionFallback: "Temperature / interest level for leads and contacts.",
    noteTitleKey: "customers.tags.manage.noteTitle.customers.temperature",
    noteTitleFallback: "Temperature / Interest",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.temperature",
    noteDescriptionFallback: "Use temperature to quickly classify contact interest level from hot to cold."
  },
  {
    kind: "renewal-quarters",
    icon: CalendarDays,
    shortLabelKey: "customers.personTags.category.renewal-quarters",
    shortLabelFallback: "Renewal",
    descriptionKey: "customers.tags.manage.description.customers.renewal_quarter",
    descriptionFallback: "Renewal quarter labels for tracking contract renewal timing.",
    noteTitleKey: "customers.tags.manage.noteTitle.customers.renewal_quarter",
    noteTitleFallback: "Renewal quarter",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.renewal_quarter",
    noteDescriptionFallback: "Assign renewal quarters to track when contracts or subscriptions are up for renewal."
  },
  {
    kind: "person-company-roles",
    icon: Users,
    shortLabelKey: "customers.personTags.category.person-company-roles",
    shortLabelFallback: "Roles",
    descriptionKey: "customers.tags.manage.description.customers.person_company_role",
    descriptionFallback: "Person-company relationship roles such as decision maker, influencer, or budget holder.",
    noteTitleKey: "customers.tags.manage.noteTitle.customers.person_company_role",
    noteTitleFallback: "Person-company roles",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.person_company_role",
    noteDescriptionFallback: "Use roles to classify how a person relates to a company, for example decision maker, technical evaluator, or primary contact."
  },
  {
    kind: "activity-types",
    icon: CalendarDays,
    shortLabelKey: "customers.personTags.category.activity-types",
    shortLabelFallback: "Activity",
    descriptionKey: "customers.tags.manage.description.customers.activity_type",
    descriptionFallback: "Activity types for calls, emails, meetings, and other CRM interactions.",
    noteTitleKey: "customers.tags.manage.noteTitle.customers.activity_type",
    noteTitleFallback: "Activity types",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.activity_type",
    noteDescriptionFallback: "Keep activity type names consistent so timeline filters remain readable across CRM views."
  },
  {
    kind: "deal-statuses",
    icon: Tag,
    shortLabelKey: "customers.personTags.category.deal-statuses",
    shortLabelFallback: "Deal status",
    descriptionKey: "customers.tags.manage.description.customers.deal_status",
    descriptionFallback: "Deal status labels used in pipeline views and deal detail cards.",
    noteTitleKey: "customers.tags.manage.noteTitle.customers.deal_status",
    noteTitleFallback: "Deal statuses",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.deal_status",
    noteDescriptionFallback: "Deal status values affect pipeline filtering and reporting groupings."
  },
  {
    kind: "industries",
    icon: Hash,
    shortLabelKey: "customers.personTags.category.industries",
    shortLabelFallback: "Industry",
    descriptionKey: "customers.config.dictionaries.sections.industries.description",
    descriptionFallback: "Industry classification labels for companies and contacts.",
    noteTitleKey: "customers.tags.manage.noteTitle.customers.industry",
    noteTitleFallback: "Industry labels",
    noteDescriptionKey: "customers.tags.manage.noteDescription.customers.industry",
    noteDescriptionFallback: "Add industry categories that match your target market segments for consistent CRM classification."
  }
];
const BUILTIN_CATEGORY_KINDS = new Set(BUILTIN_CATEGORIES.map((category) => category.kind));
function createLocalId() {
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
    return crypto.randomUUID();
  }
  return `draft-${Math.random().toString(36).slice(2)}`;
}
function normalizeColor(value) {
  if (typeof value !== "string") return "#D1D5DB";
  const trimmed = value.trim();
  if (/^#([0-9a-fA-F]{6})$/.test(trimmed)) {
    return `#${trimmed.slice(1).toLowerCase()}`;
  }
  return "#D1D5DB";
}
function slugifyLabel(value) {
  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
}
function sanitizeIcon(value) {
  return typeof value === "string" ? value.trim() : "";
}
function humanizeCategoryKind(kind) {
  return kind.split(/[-_]+/).filter((part) => part.trim().length > 0).map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
}
function createCustomCategoryDef(kind) {
  const label = humanizeCategoryKind(kind);
  return {
    kind,
    icon: Hash,
    shortLabelKey: "",
    shortLabelFallback: label,
    descriptionKey: "customers.tags.manage.customCategoryDescription",
    descriptionFallback: `Custom CRM category: ${label}.`,
    noteTitleKey: "customers.tags.manage.customCategoryNoteTitle",
    noteTitleFallback: "Custom category",
    noteDescriptionKey: "customers.tags.manage.customCategoryNoteDescription",
    noteDescriptionFallback: "Use this category to group and manage additional CRM values for your team.",
    isCustom: true
  };
}
function makeDraftEntry(entry) {
  const id = typeof entry.id === "string" ? entry.id : null;
  const value = typeof entry.value === "string" ? entry.value.trim() : "";
  if (!value.length) return null;
  return {
    localId: id ?? createLocalId(),
    id,
    value,
    label: typeof entry.label === "string" && entry.label.trim().length ? entry.label.trim() : value,
    color: normalizeColor(typeof entry.color === "string" ? entry.color : null),
    icon: sanitizeIcon(typeof entry.icon === "string" ? entry.icon : null),
    isDefault: false,
    isInherited: typeof entry.isInherited === "boolean" ? entry.isInherited : false,
    manualValue: true,
    deleted: false
  };
}
function cloneDrafts(entries) {
  return entries.map((entry) => ({ ...entry }));
}
function serializeEntries(entries) {
  return JSON.stringify(
    entries.filter((entry) => !entry.deleted).map((entry) => ({
      id: entry.id,
      value: entry.value,
      label: entry.label,
      color: entry.color,
      icon: entry.icon
    }))
  );
}
function SortableEntryRow({
  entry,
  index,
  total,
  isDefault,
  onLabelChange,
  onValueChange,
  onColorChange,
  onDelete,
  onMoveUp,
  onMoveDown,
  t
}) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: entry.localId
  });
  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1
  };
  const isFirst = index === 0;
  const isLast = index === total - 1;
  return /* @__PURE__ */ jsxs(
    "div",
    {
      ref: setNodeRef,
      style,
      className: "flex items-center gap-2.5 rounded-md border border-border bg-card px-2.5 py-2",
      children: [
        /* @__PURE__ */ jsx(
          "div",
          {
            "aria-label": t("customers.tags.manage.dragHandle", "Drag to reorder"),
            title: t("customers.tags.manage.dragHandle", "Drag to reorder"),
            className: "flex size-5 shrink-0 cursor-grab items-center justify-center text-muted-foreground/70",
            ...attributes,
            ...listeners,
            children: /* @__PURE__ */ jsx(GripVertical, { className: "size-3.5" })
          }
        ),
        /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-col gap-0.5", children: [
          /* @__PURE__ */ jsx(
            IconButton,
            {
              type: "button",
              variant: "ghost",
              size: "xs",
              "aria-label": t("customers.tags.manage.moveUp", "Move up"),
              disabled: isFirst,
              onClick: onMoveUp,
              className: "h-5 w-5 text-muted-foreground hover:text-foreground disabled:opacity-40",
              children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-3" })
            }
          ),
          /* @__PURE__ */ jsx(
            IconButton,
            {
              type: "button",
              variant: "ghost",
              size: "xs",
              "aria-label": t("customers.tags.manage.moveDown", "Move down"),
              disabled: isLast,
              onClick: onMoveDown,
              className: "h-5 w-5 text-muted-foreground hover:text-foreground disabled:opacity-40",
              children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-3" })
            }
          )
        ] }),
        /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
          /* @__PURE__ */ jsx(
            "input",
            {
              type: "text",
              value: entry.label,
              onChange: (e) => onLabelChange(e.target.value),
              className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm font-medium text-foreground outline-none focus:border-foreground"
            }
          ),
          isDefault && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
            /* @__PURE__ */ jsx(Check, { className: "size-2.5 text-status-success-icon" }),
            /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("customers.tags.manage.defaultEntry", "default when creating new records") })
          ] })
        ] }),
        /* @__PURE__ */ jsx("div", { className: "w-[140px] shrink-0", children: /* @__PURE__ */ jsx(
          "input",
          {
            type: "text",
            value: entry.value,
            onChange: (e) => onValueChange(slugifyLabel(e.target.value)),
            className: "w-full rounded-md bg-muted px-2.5 py-2 text-xs font-medium text-muted-foreground outline-none"
          }
        ) }),
        /* @__PURE__ */ jsx(
          ColorPicker,
          {
            value: normalizeColor(entry.color),
            onChange: (next) => onColorChange(normalizeColor(next)),
            size: "sm",
            className: "shrink-0"
          }
        ),
        /* @__PURE__ */ jsx(
          IconButton,
          {
            type: "button",
            variant: "ghost",
            size: "sm",
            className: "size-8 shrink-0 text-muted-foreground hover:text-destructive",
            onClick: onDelete,
            "aria-label": t("customers.tags.manage.delete", "Delete"),
            children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5" })
          }
        )
      ]
    }
  );
}
function ManageTagsDialog({ open, onClose }) {
  const t = useT();
  const [categories, setCategories] = React.useState(BUILTIN_CATEGORIES);
  const [activeTab, setActiveTab] = React.useState(BUILTIN_CATEGORIES[0].kind);
  const [loading, setLoading] = React.useState(true);
  const [saving, setSaving] = React.useState(false);
  const [searchValue, setSearchValue] = React.useState("");
  const [entryCounts, setEntryCounts] = React.useState({});
  const [draftsByKind, setDraftsByKind] = React.useState({});
  const [originalByKind, setOriginalByKind] = React.useState({});
  const [createCategoryOpen, setCreateCategoryOpen] = React.useState(false);
  const [newCategoryName, setNewCategoryName] = React.useState("");
  const [newCategorySelectionMode, setNewCategorySelectionMode] = React.useState("multi");
  const [creatingCategory, setCreatingCategory] = React.useState(false);
  const [canScrollLeft, setCanScrollLeft] = React.useState(false);
  const [canScrollRight, setCanScrollRight] = React.useState(false);
  const categoryRailRef = React.useRef(null);
  const { runMutation, retryLastMutation } = useGuardedMutation({
    contextId: "customers-manage-tags",
    blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
  });
  const mutationContext = React.useMemo(
    () => ({
      formId: "customers-manage-tags",
      resourceKind: "customers.dictionary_entry",
      resourceId: "bulk",
      retryLastMutation
    }),
    [retryLastMutation]
  );
  const runGuardedMutation = React.useCallback(
    async (operation, mutationPayload) => runMutation({
      operation,
      mutationPayload,
      context: mutationContext
    }),
    [mutationContext, runMutation]
  );
  const translatedCategories = React.useMemo(
    () => categories.map((category) => ({
      ...category,
      shortLabel: category.shortLabelKey ? t(category.shortLabelKey, category.shortLabelFallback) : category.shortLabelFallback,
      description: category.descriptionKey ? t(
        category.descriptionKey,
        category.descriptionFallback,
        category.isCustom ? { name: category.shortLabelFallback } : void 0
      ) : category.descriptionFallback,
      noteTitle: category.noteTitleKey ? t(category.noteTitleKey, category.noteTitleFallback) : category.noteTitleFallback,
      noteDescription: category.noteDescriptionKey ? t(category.noteDescriptionKey, category.noteDescriptionFallback) : category.noteDescriptionFallback
    })),
    [categories, t]
  );
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
    useSensor(KeyboardSensor)
  );
  const loadData = React.useCallback(async () => {
    setLoading(true);
    try {
      let kindSettings = [];
      try {
        const settings = await readApiResultOrThrow(
          "/api/customers/dictionaries/kind-settings",
          { cache: "no-store" }
        );
        kindSettings = Array.isArray(settings?.items) ? settings.items : [];
      } catch {
        kindSettings = [];
      }
      const customCategories = kindSettings.filter((setting) => !BUILTIN_CATEGORY_KINDS.has(setting.kind)).sort((left, right) => left.sortOrder - right.sortOrder || left.kind.localeCompare(right.kind)).map((setting) => createCustomCategoryDef(setting.kind));
      const resolvedCategories = [...BUILTIN_CATEGORIES, ...customCategories];
      const loadedDrafts = {};
      const counts = {};
      for (const category of resolvedCategories) {
        try {
          const data = await readApiResultOrThrow(`/api/customers/dictionaries/${category.kind}`, { cache: "no-store" });
          const entries = Array.isArray(data?.items) ? data.items.map(makeDraftEntry).filter((entry) => entry !== null) : [];
          loadedDrafts[category.kind] = entries;
          counts[category.kind] = entries.length;
        } catch {
          loadedDrafts[category.kind] = [];
          counts[category.kind] = 0;
        }
      }
      setCategories(resolvedCategories);
      setDraftsByKind(
        Object.fromEntries(
          Object.entries(loadedDrafts).map(([k, v]) => [k, cloneDrafts(v)])
        )
      );
      setOriginalByKind(
        Object.fromEntries(
          Object.entries(loadedDrafts).map(([k, v]) => [k, cloneDrafts(v)])
        )
      );
      setEntryCounts(counts);
      setActiveTab(
        (current) => resolvedCategories.some((category) => category.kind === current) ? current : resolvedCategories[0]?.kind ?? BUILTIN_CATEGORIES[0].kind
      );
    } catch (error) {
      const message = error instanceof Error ? error.message : t("customers.tags.manage.loadError", "Failed to load tag dictionaries.");
      flash(message, "error");
    } finally {
      setLoading(false);
    }
  }, [t]);
  React.useEffect(() => {
    if (!open) return;
    setSearchValue("");
    setCreateCategoryOpen(false);
    setNewCategoryName("");
    setNewCategorySelectionMode("multi");
    loadData().catch((err) => logger.warn("loadData failed", { component: "ManageTagsDialog", err }));
  }, [loadData, open]);
  const activeMeta = translatedCategories.find((category) => category.kind === activeTab) ?? null;
  const activeEntries = draftsByKind[activeTab] ?? [];
  const visibleEntries = React.useMemo(() => {
    const query = searchValue.trim().toLowerCase();
    return activeEntries.filter((entry) => {
      if (entry.deleted) return false;
      if (!query) return true;
      return entry.label.toLowerCase().includes(query) || entry.value.toLowerCase().includes(query);
    });
  }, [activeEntries, searchValue]);
  const hasChanges = React.useMemo(
    () => categories.some((category) => {
      const original = originalByKind[category.kind] ?? [];
      const current = draftsByKind[category.kind] ?? [];
      return serializeEntries(original) !== serializeEntries(current);
    }),
    [categories, draftsByKind, originalByKind]
  );
  const updateDraftEntry = React.useCallback(
    (kind, localId, updater) => {
      setDraftsByKind((current) => ({
        ...current,
        [kind]: (current[kind] ?? []).map(
          (entry) => entry.localId === localId ? updater(entry) : entry
        )
      }));
    },
    []
  );
  const handleAddEntry = React.useCallback(() => {
    setDraftsByKind((current) => ({
      ...current,
      [activeTab]: [
        ...current[activeTab] ?? [],
        {
          localId: createLocalId(),
          id: null,
          value: "",
          label: "",
          color: "#D1D5DB",
          icon: "",
          isDefault: false,
          isInherited: false,
          manualValue: false,
          deleted: false
        }
      ]
    }));
  }, [activeTab]);
  const handleDeleteEntry = React.useCallback(
    (kind, localId) => {
      setDraftsByKind((current) => {
        const nextEntries = (current[kind] ?? []).map((entry) => {
          if (entry.localId !== localId) return entry;
          if (!entry.id) return null;
          return { ...entry, deleted: true };
        }).filter((entry) => entry !== null);
        return { ...current, [kind]: nextEntries };
      });
    },
    []
  );
  const handleDragEnd = React.useCallback(
    (event) => {
      const { active, over } = event;
      if (!over || active.id === over.id) return;
      setDraftsByKind((current) => {
        const entries = current[activeTab] ?? [];
        const liveEntries = entries.filter((e) => !e.deleted);
        const oldIndex = liveEntries.findIndex((e) => e.localId === active.id);
        const newIndex = liveEntries.findIndex((e) => e.localId === over.id);
        if (oldIndex === -1 || newIndex === -1) return current;
        const reordered = arrayMove(liveEntries, oldIndex, newIndex);
        const deletedEntries = entries.filter((e) => e.deleted);
        return { ...current, [activeTab]: [...reordered, ...deletedEntries] };
      });
    },
    [activeTab]
  );
  const moveEntryByDelta = React.useCallback(
    (localId, delta) => {
      setDraftsByKind((current) => {
        const entries = current[activeTab] ?? [];
        const liveEntries = entries.filter((entry) => !entry.deleted);
        const oldIndex = liveEntries.findIndex((entry) => entry.localId === localId);
        if (oldIndex < 0) return current;
        const newIndex = oldIndex + delta;
        if (newIndex < 0 || newIndex >= liveEntries.length) return current;
        const reordered = arrayMove(liveEntries, oldIndex, newIndex);
        const deletedEntries = entries.filter((entry) => entry.deleted);
        return { ...current, [activeTab]: [...reordered, ...deletedEntries] };
      });
    },
    [activeTab]
  );
  const handleSave = React.useCallback(async () => {
    if (saving) return;
    for (const category of categories) {
      const entries = draftsByKind[category.kind] ?? [];
      for (const entry of entries) {
        if (entry.deleted) continue;
        const nextLabel = entry.label.trim();
        const nextValue = entry.value.trim();
        if (!nextLabel || !nextValue) {
          flash(
            t(
              "customers.tags.manage.validation.required",
              "Each entry must have both a label and a slug before saving."
            ),
            "error"
          );
          return;
        }
      }
    }
    setSaving(true);
    try {
      for (const category of categories) {
        const currentEntries = draftsByKind[category.kind] ?? [];
        const originalEntries = originalByKind[category.kind] ?? [];
        const originalById = new Map(
          originalEntries.filter((e) => e.id).map((e) => [e.id, e])
        );
        for (const entry of currentEntries) {
          if (entry.deleted) {
            if (entry.id) {
              await runGuardedMutation(
                () => (
                  // optimistic-lock-exempt: tag dictionary entry assignment add/remove
                  apiCallOrThrow(`/api/customers/dictionaries/${category.kind}/${entry.id}`, {
                    method: "DELETE"
                  })
                ),
                { kind: category.kind, entryId: entry.id, operation: "delete" }
              );
            }
            continue;
          }
          const payload = {
            value: entry.value.trim(),
            label: entry.label.trim(),
            color: normalizeColor(entry.color),
            icon: sanitizeIcon(entry.icon) || null
          };
          if (!entry.id) {
            await runGuardedMutation(
              () => (
                // optimistic-lock-exempt: tag dictionary entry create-only
                apiCallOrThrow(`/api/customers/dictionaries/${category.kind}`, {
                  method: "POST",
                  headers: { "content-type": "application/json" },
                  body: JSON.stringify(payload)
                })
              ),
              { kind: category.kind, value: payload.value, operation: "create" }
            );
            continue;
          }
          if (entry.isInherited) continue;
          const originalEntry = originalById.get(entry.id);
          if (originalEntry && originalEntry.value === payload.value && originalEntry.label === payload.label && normalizeColor(originalEntry.color) === normalizeColor(payload.color) && sanitizeIcon(originalEntry.icon) === sanitizeIcon(payload.icon)) {
            continue;
          }
          await runGuardedMutation(
            () => (
              // optimistic-lock-exempt: tag dictionary entry assignment add/remove
              apiCallOrThrow(`/api/customers/dictionaries/${category.kind}/${entry.id}`, {
                method: "PATCH",
                headers: { "content-type": "application/json" },
                body: JSON.stringify(payload)
              })
            ),
            { kind: category.kind, entryId: entry.id, value: payload.value, operation: "update" }
          );
        }
      }
      flash(t("customers.tags.manage.saveSuccess", "Tag dictionaries updated."), "success");
      await loadData();
    } catch (error) {
      const message = error instanceof Error ? error.message : t("customers.tags.manage.saveError", "Failed to save tag dictionaries.");
      flash(message, "error");
    } finally {
      setSaving(false);
    }
  }, [categories, draftsByKind, loadData, originalByKind, runGuardedMutation, saving, t]);
  const updateCategoryRailState = React.useCallback(() => {
    const rail = categoryRailRef.current;
    if (!rail) {
      setCanScrollLeft(false);
      setCanScrollRight(false);
      return;
    }
    const maxScrollLeft = Math.max(0, rail.scrollWidth - rail.clientWidth);
    setCanScrollLeft(rail.scrollLeft > 4);
    setCanScrollRight(rail.scrollLeft < maxScrollLeft - 4);
  }, []);
  const scrollCategoryRail = React.useCallback(
    (direction) => {
      const rail = categoryRailRef.current;
      if (!rail) return;
      const offset = Math.max(180, Math.round(rail.clientWidth * 0.65));
      rail.scrollBy({
        left: direction === "left" ? -offset : offset,
        behavior: "smooth"
      });
    },
    []
  );
  React.useEffect(() => {
    if (!open) return;
    const rail = categoryRailRef.current;
    if (!rail) return;
    updateCategoryRailState();
    rail.addEventListener("scroll", updateCategoryRailState, { passive: true });
    const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => updateCategoryRailState()) : null;
    resizeObserver?.observe(rail);
    return () => {
      rail.removeEventListener("scroll", updateCategoryRailState);
      resizeObserver?.disconnect();
    };
  }, [open, translatedCategories, updateCategoryRailState]);
  const handleCreateCategory = React.useCallback(async () => {
    if (creatingCategory) return;
    const trimmedName = newCategoryName.trim();
    const kind = slugifyLabel(trimmedName);
    if (!kind.length) {
      flash(
        t("customers.tags.manage.addCategoryRequired", "Enter a category name first."),
        "error"
      );
      return;
    }
    if (categories.some((category) => category.kind === kind)) {
      setActiveTab(kind);
      setCreateCategoryOpen(false);
      return;
    }
    setCreatingCategory(true);
    try {
      await runGuardedMutation(
        () => (
          // optimistic-lock-exempt: tag dictionary kind-settings assignment add/remove
          apiCallOrThrow("/api/customers/dictionaries/kind-settings", {
            method: "PATCH",
            headers: { "content-type": "application/json" },
            body: JSON.stringify({
              kind,
              selectionMode: newCategorySelectionMode,
              visibleInTags: true,
              sortOrder: categories.length + 1
            })
          })
        ),
        {
          kind,
          selectionMode: newCategorySelectionMode,
          operation: "createCategory"
        }
      );
      await loadData();
      setActiveTab(kind);
      setCreateCategoryOpen(false);
      setNewCategoryName("");
      setNewCategorySelectionMode("multi");
      flash(t("customers.tags.manage.createCategorySuccess", "Category created."), "success");
    } catch (error) {
      const message = error instanceof Error ? error.message : t("customers.tags.manage.createCategoryError", "Failed to create category.");
      flash(message, "error");
    } finally {
      setCreatingCategory(false);
    }
  }, [categories, creatingCategory, loadData, newCategoryName, newCategorySelectionMode, runGuardedMutation, t]);
  React.useEffect(() => {
    if (!open) return;
    const handler = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
        e.preventDefault();
        void handleSave();
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [open, handleSave]);
  return /* @__PURE__ */ jsx(
    Dialog,
    {
      open,
      onOpenChange: (nextOpen) => {
        if (!nextOpen) onClose();
      },
      children: /* @__PURE__ */ jsxs(
        DialogContent,
        {
          className: "flex max-h-[90vh] flex-col overflow-hidden border-border p-0 shadow-[0px_20px_48px_0px_rgba(0,0,0,0.18)] sm:max-w-[820px] sm:rounded-lg [&>[data-dialog-close]]:hidden",
          "aria-describedby": void 0,
          children: [
            /* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("customers.tags.manage.title", "Manage tags") }) }),
            /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between pb-2.5 pl-6 pr-5 pt-4", children: [
              /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
                /* @__PURE__ */ jsx("h2", { className: "text-base font-bold leading-tight text-foreground", children: t("customers.tags.manage.title", "Manage tags") }),
                /* @__PURE__ */ jsx("p", { className: "text-xs leading-tight text-muted-foreground", children: t(
                  "customers.tags.manage.subtitle",
                  "Tag dictionaries for the entire tenant"
                ) })
              ] }),
              /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
                /* @__PURE__ */ jsxs(
                  Button,
                  {
                    type: "button",
                    variant: "outline",
                    size: "sm",
                    className: "h-auto gap-1.5 rounded-md px-3 py-2 text-xs font-semibold",
                    onClick: () => {
                      setCreateCategoryOpen((current) => !current);
                      setNewCategoryName("");
                      setNewCategorySelectionMode("multi");
                    },
                    children: [
                      /* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
                      t("customers.tags.manage.addCategory", "New category")
                    ]
                  }
                ),
                /* @__PURE__ */ jsx(
                  IconButton,
                  {
                    type: "button",
                    variant: "outline",
                    size: "sm",
                    className: "size-7 shrink-0 rounded-md border-border",
                    onClick: onClose,
                    "aria-label": t("customers.tags.manage.closeDialog", "Close"),
                    children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
                  }
                )
              ] })
            ] }),
            /* @__PURE__ */ jsx("div", { className: "h-px shrink-0 bg-border" }),
            loading ? /* @__PURE__ */ jsx("div", { className: "px-7 py-12 text-center text-sm text-muted-foreground", children: t("customers.tags.manage.loading", "Loading...") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
              createCategoryOpen ? /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-2.5 border-b border-border px-6 py-3", children: [
                /* @__PURE__ */ jsx("div", { className: "min-w-[220px] flex-1 rounded-md border border-input bg-background px-3 py-2", children: /* @__PURE__ */ jsx(
                  "input",
                  {
                    type: "text",
                    value: newCategoryName,
                    onChange: (event) => setNewCategoryName(event.target.value),
                    onKeyDown: (event) => {
                      if (event.key === "Enter") {
                        event.preventDefault();
                        void handleCreateCategory();
                      }
                    },
                    placeholder: t("customers.tags.manage.addCategoryPlaceholder", "Category name..."),
                    className: "w-full bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
                  }
                ) }),
                /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 rounded-md border border-border bg-muted/60 p-1", children: [
                  /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      variant: newCategorySelectionMode === "single" ? "secondary" : "ghost",
                      size: "sm",
                      className: "h-auto rounded-md px-2.5 py-1.5 text-xs",
                      onClick: () => setNewCategorySelectionMode("single"),
                      children: t("customers.tags.manage.categoryMode.single", "Single")
                    }
                  ),
                  /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      variant: newCategorySelectionMode === "multi" ? "secondary" : "ghost",
                      size: "sm",
                      className: "h-auto rounded-md px-2.5 py-1.5 text-xs",
                      onClick: () => setNewCategorySelectionMode("multi"),
                      children: t("customers.tags.manage.categoryMode.multi", "Multi")
                    }
                  )
                ] }),
                /* @__PURE__ */ jsx(
                  Button,
                  {
                    type: "button",
                    size: "sm",
                    className: "h-auto rounded-md px-3 py-2 text-xs font-semibold",
                    onClick: () => {
                      void handleCreateCategory();
                    },
                    disabled: creatingCategory,
                    children: creatingCategory ? t("customers.tags.manage.creatingCategory", "Creating...") : t("customers.tags.manage.createCategory", "Create category")
                  }
                )
              ] }) : null,
              /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-end gap-2 border-b border-input px-4 pt-1.5", children: [
                /* @__PURE__ */ jsx(
                  IconButton,
                  {
                    type: "button",
                    variant: "ghost",
                    size: "sm",
                    className: "size-8 shrink-0 self-center rounded-full",
                    onClick: () => scrollCategoryRail("left"),
                    disabled: !canScrollLeft,
                    "aria-label": t("customers.tags.manage.scrollLeft", "Scroll categories left"),
                    children: /* @__PURE__ */ jsx(ChevronsLeft, { className: "size-3.5" })
                  }
                ),
                /* @__PURE__ */ jsx(
                  "div",
                  {
                    ref: categoryRailRef,
                    className: "scrollbar-hide min-w-0 flex-1 overflow-x-auto",
                    children: /* @__PURE__ */ jsx("div", { className: "flex items-end gap-0.5", children: translatedCategories.map((category) => {
                      const Icon = category.icon;
                      const isActive = category.kind === activeTab;
                      const count = entryCounts[category.kind] ?? 0;
                      return /* @__PURE__ */ jsxs(
                        Button,
                        {
                          type: "button",
                          variant: "ghost",
                          size: "sm",
                          onClick: () => {
                            setActiveTab(category.kind);
                            setSearchValue("");
                          },
                          className: `flex h-auto shrink-0 items-center gap-1.5 rounded-none border-b-2 px-2.5 py-2 hover:bg-transparent -mb-px ${isActive ? "border-accent-indigo text-foreground" : "border-transparent text-muted-foreground"}`,
                          children: [
                            /* @__PURE__ */ jsx(Icon, { className: "size-3.5" }),
                            /* @__PURE__ */ jsx(
                              "span",
                              {
                                className: `whitespace-nowrap text-xs ${isActive ? "font-semibold" : "font-medium"}`,
                                children: category.shortLabel
                              }
                            ),
                            /* @__PURE__ */ jsx("span", { className: "rounded-sm bg-muted px-1 py-px text-overline font-semibold text-foreground", children: count })
                          ]
                        },
                        category.kind
                      );
                    }) })
                  }
                ),
                /* @__PURE__ */ jsx(
                  IconButton,
                  {
                    type: "button",
                    variant: "ghost",
                    size: "sm",
                    className: "size-8 shrink-0 self-center rounded-full",
                    onClick: () => scrollCategoryRail("right"),
                    disabled: !canScrollRight,
                    "aria-label": t("customers.tags.manage.scrollRight", "Scroll categories right"),
                    children: /* @__PURE__ */ jsx(ChevronsRight, { className: "size-3.5" })
                  }
                )
              ] }),
              /* @__PURE__ */ jsx(ScrollArea, { className: "min-h-0 flex-1", viewportClassName: "px-6 py-3.5", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: activeMeta ? /* @__PURE__ */ jsxs(Fragment, { children: [
                /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
                  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
                    /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
                      /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-foreground", children: activeMeta.shortLabel }),
                      (activeMeta.badges ?? []).map((badge) => /* @__PURE__ */ jsx(
                        Badge,
                        {
                          variant: badge === "required" ? "warning" : "muted",
                          size: "sm",
                          children: badge === "required" ? t("customers.tags.manage.badge.required", "REQUIRED") : t("customers.tags.manage.badge.system", "SYSTEM")
                        },
                        badge
                      ))
                    ] }),
                    /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
                      /* @__PURE__ */ jsx(Info, { className: "size-3 shrink-0 text-muted-foreground" }),
                      /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: activeMeta.description })
                    ] })
                  ] }),
                  /* @__PURE__ */ jsxs("div", { className: "relative w-[220px] shrink-0", children: [
                    /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground/70" }),
                    /* @__PURE__ */ jsx(
                      "input",
                      {
                        type: "text",
                        value: searchValue,
                        onChange: (e) => setSearchValue(e.target.value),
                        placeholder: t("customers.tags.manage.search", "Search values..."),
                        className: "w-full rounded-md border border-input bg-background py-2 pl-9 pr-3 text-xs text-foreground outline-none placeholder:text-muted-foreground/70 focus:border-foreground"
                      }
                    )
                  ] })
                ] }),
                /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-3 py-1.5", children: [
                  /* @__PURE__ */ jsx("div", { className: "w-[18px] shrink-0" }),
                  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx("span", { className: "text-overline font-medium uppercase tracking-wider text-muted-foreground", children: t("customers.tags.manage.columns.label", "LABEL") }) }),
                  /* @__PURE__ */ jsx("div", { className: "w-[140px] shrink-0", children: /* @__PURE__ */ jsx("span", { className: "text-overline font-medium uppercase tracking-wider text-muted-foreground", children: t("customers.tags.manage.columns.slug", "SLUG") }) }),
                  /* @__PURE__ */ jsx("div", { className: "w-[80px] shrink-0", children: /* @__PURE__ */ jsx("span", { className: "text-overline font-medium uppercase tracking-wider text-muted-foreground", children: t("customers.tags.manage.columns.color", "COLOR") }) }),
                  /* @__PURE__ */ jsx("div", { className: "w-[32px] shrink-0" })
                ] }),
                /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
                  /* @__PURE__ */ jsx(
                    DndContext,
                    {
                      sensors,
                      collisionDetection: closestCenter,
                      onDragEnd: handleDragEnd,
                      children: /* @__PURE__ */ jsx(
                        SortableContext,
                        {
                          items: visibleEntries.map((e) => e.localId),
                          strategy: verticalListSortingStrategy,
                          children: visibleEntries.map((entry, index) => /* @__PURE__ */ jsx(
                            SortableEntryRow,
                            {
                              entry,
                              index,
                              total: visibleEntries.length,
                              isDefault: index === 0 && entry.id !== null,
                              onLabelChange: (value) => {
                                updateDraftEntry(activeTab, entry.localId, (current) => ({
                                  ...current,
                                  label: value,
                                  value: current.manualValue ? current.value : slugifyLabel(value)
                                }));
                              },
                              onValueChange: (value) => {
                                updateDraftEntry(activeTab, entry.localId, (current) => ({
                                  ...current,
                                  value,
                                  manualValue: true
                                }));
                              },
                              onColorChange: (value) => {
                                updateDraftEntry(activeTab, entry.localId, (current) => ({
                                  ...current,
                                  color: value
                                }));
                              },
                              onDelete: () => handleDeleteEntry(activeTab, entry.localId),
                              onMoveUp: () => moveEntryByDelta(entry.localId, -1),
                              onMoveDown: () => moveEntryByDelta(entry.localId, 1),
                              t
                            },
                            entry.localId
                          ))
                        }
                      )
                    }
                  ),
                  visibleEntries.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: t(
                    "customers.tags.manage.noMatches",
                    "No entries match the current search."
                  ) })
                ] }),
                /* @__PURE__ */ jsxs(
                  Button,
                  {
                    type: "button",
                    variant: "ghost",
                    onClick: handleAddEntry,
                    className: "flex h-auto w-full items-center justify-center gap-2 rounded-md border border-dashed border-border bg-background p-3 text-xs font-semibold text-foreground hover:bg-muted",
                    children: [
                      /* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
                      t("customers.tags.manage.addValue", "Add new value")
                    ]
                  }
                ),
                /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5 rounded-md bg-muted px-3.5 py-3", children: [
                  /* @__PURE__ */ jsx(Info, { className: "mt-0.5 size-3.5 shrink-0 text-muted-foreground" }),
                  /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-1", children: [
                    /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-foreground", children: activeMeta.noteTitle }),
                    /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: activeMeta.noteDescription })
                  ] })
                ] })
              ] }) : /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground", children: t("customers.tags.manage.noDictionaries", "No tag categories found.") }) }) }),
              /* @__PURE__ */ jsx("div", { className: "h-px shrink-0 bg-border" }),
              /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between px-6 py-3", children: [
                /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
                  /* @__PURE__ */ jsx(Info, { className: "size-3 shrink-0 text-muted-foreground" }),
                  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
                    "customers.tags.manage.tenantNotice",
                    "Changes apply to the entire tenant \xB7 visible immediately"
                  ) })
                ] }),
                /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
                  /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      variant: "outline",
                      onClick: onClose,
                      className: "rounded-md border-border px-4 py-2.5 text-sm font-semibold text-foreground",
                      children: t("customers.tags.manage.close", "Cancel")
                    }
                  ),
                  /* @__PURE__ */ jsxs(
                    Button,
                    {
                      type: "button",
                      onClick: () => {
                        void handleSave();
                      },
                      disabled: saving || !hasChanges,
                      className: "rounded-md bg-foreground px-4 py-2.5 text-sm font-semibold text-background hover:bg-foreground/90",
                      children: [
                        /* @__PURE__ */ jsx(Save, { className: "mr-2 size-4" }),
                        saving ? t("customers.tags.manage.saving", "Saving...") : t("customers.tags.manage.save", "Save changes")
                      ]
                    }
                  )
                ] })
              ] })
            ] })
          ]
        }
      )
    }
  );
}
export {
  ManageTagsDialog
};
//# sourceMappingURL=ManageTagsDialog.js.map
