"use client";
import { jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { Pencil, X } from "lucide-react";
import { Button } from "@open-mercato/ui/primitives/button";
import { TagsInput } from "@open-mercato/ui/backend/inputs/TagsInput";
import { DataLoader } from "@open-mercato/ui/primitives/DataLoader";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { ComponentReplacementHandles } from "@open-mercato/shared/modules/widgets/component-registry";
import { useRegisteredComponent } from "../injection/useRegisteredComponent.js";
function normalizeTagLabels(labels) {
  return Array.from(
    new Set(
      labels.map((label) => label.trim().toLowerCase()).filter((label) => label.length > 0)
    )
  ).sort();
}
function buildTagLabelKey(labels) {
  return normalizeTagLabels(labels).join("\0");
}
function TagsSectionImpl({
  title,
  tags,
  onChange,
  isSubmitting = false,
  canEdit = true,
  autoSave = false,
  loadOptions,
  createTag,
  onSave,
  labels,
  controllerRef
}) {
  const [editing, setEditing] = React.useState(autoSave);
  const [draft, setDraft] = React.useState([]);
  const [saving, setSaving] = React.useState(false);
  const [, setOptions] = React.useState(() => /* @__PURE__ */ new Map());
  const [loadingOptions, setLoadingOptions] = React.useState(false);
  const [error, setError] = React.useState(null);
  const draftRef = React.useRef([]);
  const savedTagsRef = React.useRef(tags);
  const optionsRef = React.useRef(/* @__PURE__ */ new Map());
  const saveTaskRef = React.useRef(null);
  React.useEffect(() => {
    savedTagsRef.current = tags;
    setOptions((prev) => {
      const next = new Map(prev);
      for (const tag of tags) {
        next.set(tag.label.toLowerCase(), tag);
      }
      optionsRef.current = next;
      return next;
    });
  }, [tags]);
  React.useEffect(() => {
    draftRef.current = draft;
  }, [draft]);
  const syncFetchedOptions = React.useCallback((fetched) => {
    if (!fetched.length) return;
    setOptions((prev) => {
      const next = new Map(prev);
      for (const tag of fetched) {
        next.set(tag.label.toLowerCase(), tag);
      }
      optionsRef.current = next;
      return next;
    });
  }, []);
  const hasPendingDraftChanges = React.useCallback(() => {
    if (!autoSave || !autoSaveUserEditedRef.current) return false;
    const draftLabels = normalizeTagLabels(draftRef.current);
    const savedLabels = normalizeTagLabels(savedTagsRef.current.map((tag) => tag.label));
    if (draftLabels.length !== savedLabels.length) return true;
    return draftLabels.some((label, index) => label !== savedLabels[index]);
  }, [autoSave]);
  const loadSuggestions = React.useCallback(
    async (query) => {
      try {
        const fetched = await loadOptions(query);
        syncFetchedOptions(fetched);
        return fetched.map((tag) => tag.label);
      } catch (err) {
        console.error("tags.section.loadSuggestions", err);
        return [];
      }
    },
    [loadOptions, syncFetchedOptions]
  );
  const startEditing = React.useCallback(async () => {
    if (editing || isSubmitting || !canEdit) return;
    setError(null);
    setDraft(tags.map((tag) => tag.label));
    setEditing(true);
    setLoadingOptions(true);
    try {
      const fetched = await loadOptions();
      syncFetchedOptions(fetched);
    } catch (err) {
      const message = err instanceof Error ? err.message : labels.loadError;
      setError(message);
      flash(message, "error");
    } finally {
      setLoadingOptions(false);
    }
  }, [canEdit, editing, isSubmitting, labels.loadError, loadOptions, syncFetchedOptions, tags]);
  const cancelEditing = React.useCallback(() => {
    setEditing(false);
    setDraft([]);
    setError(null);
  }, []);
  const ensureTagOption = React.useCallback(
    async (label) => {
      const normalized = label.trim();
      if (!normalized.length) {
        throw new Error(labels.labelRequired);
      }
      const existing = optionsRef.current.get(normalized.toLowerCase());
      if (existing) return existing;
      try {
        const created = await createTag(normalized);
        setOptions((prev) => {
          const next = new Map(prev);
          next.set(created.label.toLowerCase(), created);
          optionsRef.current = next;
          return next;
        });
        return created;
      } catch (err) {
        const message = err instanceof Error ? err.message : labels.createError;
        throw new Error(message);
      }
    },
    [createTag, labels.createError, labels.labelRequired]
  );
  const handleSave = React.useCallback(async () => {
    if (saveTaskRef.current) {
      await saveTaskRef.current;
      if (!autoSave || !hasPendingDraftChanges()) return;
    }
    if (autoSave && !hasPendingDraftChanges()) {
      autoSaveUserEditedRef.current = false;
      return;
    }
    const trimmed = draftRef.current.map((label) => label.trim()).filter((label) => label.length > 0);
    const uniqueLabels = Array.from(new Set(trimmed.map((label) => label.toLowerCase())));
    let shouldContinueAutoSave = false;
    const task = (async () => {
      const currentTags = savedTagsRef.current;
      const currentIds = new Set(currentTags.map((tag) => tag.id));
      const finalTagOptions = [];
      const submittedDraftKey = buildTagLabelKey(trimmed);
      setSaving(true);
      setError(null);
      try {
        for (const normalized of uniqueLabels) {
          const existing = optionsRef.current.get(normalized);
          if (existing) {
            finalTagOptions.push(existing);
            continue;
          }
          const matchingLabel = trimmed.find((label) => label.toLowerCase() === normalized) ?? normalized;
          const created = await ensureTagOption(matchingLabel);
          finalTagOptions.push(created);
        }
        const finalIds = new Set(finalTagOptions.map((tag) => tag.id));
        const added = finalTagOptions.filter((tag) => !currentIds.has(tag.id));
        const removed = currentTags.filter((tag) => !finalIds.has(tag.id));
        if (added.length > 0 || removed.length > 0) {
          await onSave({ next: finalTagOptions, added, removed });
        }
        savedTagsRef.current = finalTagOptions;
        onChange?.(finalTagOptions);
        if (autoSave) {
          const latestDraftKey = buildTagLabelKey(draftRef.current);
          if (latestDraftKey === submittedDraftKey) {
            autoSaveUserEditedRef.current = false;
            setDraft(finalTagOptions.map((tag) => tag.label));
          } else {
            shouldContinueAutoSave = true;
          }
        } else {
          setEditing(false);
          setDraft([]);
        }
        if (labels.success && (added.length > 0 || removed.length > 0)) flash(labels.success, "success");
      } catch (err) {
        const message = err instanceof Error ? err.message : labels.updateError;
        setError(message);
        flash(message, "error");
      } finally {
        setSaving(false);
      }
    })();
    saveTaskRef.current = task;
    try {
      await task;
    } finally {
      saveTaskRef.current = null;
    }
    if (shouldContinueAutoSave) {
      void handleSave();
    }
  }, [autoSave, ensureTagOption, hasPendingDraftChanges, labels.success, labels.updateError, onChange, onSave]);
  const activeTags = editing ? draft : tags.map((tag) => tag.label);
  const handleEditingKeyDown = React.useCallback(
    (event) => {
      if (!editing) return;
      if (event.key === "Escape") {
        event.preventDefault();
        cancelEditing();
        return;
      }
      if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
        event.preventDefault();
        if (saving || isSubmitting) return;
        void handleSave();
      }
    },
    [cancelEditing, editing, handleSave, isSubmitting, saving]
  );
  const autoSaveInitializedRef = React.useRef(false);
  React.useEffect(() => {
    if (!autoSave || autoSaveInitializedRef.current) return;
    autoSaveInitializedRef.current = true;
    setEditing(true);
    setDraft(tags.map((tag) => tag.label));
    let cancelled = false;
    loadOptions().then((fetched) => {
      if (cancelled) return;
      syncFetchedOptions(fetched);
    }).catch(() => {
    });
    return () => {
      cancelled = true;
    };
  }, [autoSave]);
  const autoSaveUserEditedRef = React.useRef(false);
  const originalOnChange = React.useCallback(
    (values) => {
      autoSaveUserEditedRef.current = true;
      setDraft(values);
    },
    []
  );
  React.useEffect(() => {
    if (!autoSave || !editing || !autoSaveUserEditedRef.current) return;
    if (!hasPendingDraftChanges()) return;
    void handleSave();
  }, [autoSave, draft, editing, handleSave, hasPendingDraftChanges]);
  const flush = React.useCallback(async () => {
    if (saveTaskRef.current) {
      await saveTaskRef.current;
      if (!autoSave || !editing || !hasPendingDraftChanges()) return;
    }
    if (!autoSave || !editing || !hasPendingDraftChanges()) return;
    await handleSave();
  }, [autoSave, editing, handleSave, hasPendingDraftChanges]);
  React.useEffect(() => {
    if (!controllerRef) return;
    controllerRef.current = { flush };
    return () => {
      if (controllerRef.current?.flush === flush) {
        controllerRef.current = null;
      }
    };
  }, [controllerRef, flush]);
  const disableInteraction = isSubmitting || !canEdit;
  const autoSaveStatusLabel = saving ? labels.saving ?? "Saving\u2026" : labels.autoSaveHint ?? null;
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
    /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between group", children: [
      /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold", children: title }),
      autoSave ? autoSaveStatusLabel ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: autoSaveStatusLabel }) : null : /* @__PURE__ */ jsxs(
        Button,
        {
          type: "button",
          variant: "ghost",
          size: "icon",
          onClick: editing ? cancelEditing : startEditing,
          disabled: disableInteraction || saving,
          className: editing ? "opacity-100 transition-opacity duration-150" : "opacity-100 md:opacity-0 transition-opacity duration-150 md:group-hover:opacity-100 focus-visible:opacity-100",
          children: [
            editing ? /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" }),
            /* @__PURE__ */ jsx("span", { className: "sr-only", children: editing ? labels.cancel ?? "Cancel" : labels.edit ?? "Edit" })
          ]
        }
      )
    ] }),
    editing ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-4 space-y-3", children: /* @__PURE__ */ jsx(
      DataLoader,
      {
        isLoading: loadingOptions,
        loadingMessage: labels.loading,
        spinnerSize: "sm",
        children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", onKeyDown: handleEditingKeyDown, children: [
          /* @__PURE__ */ jsx(
            TagsInput,
            {
              value: activeTags,
              onChange: autoSave ? originalOnChange : (values) => setDraft(values),
              placeholder: labels.placeholder,
              loadSuggestions,
              autoFocus: !autoSave
            }
          ),
          error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: error }) : null,
          autoSave ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-3 mb-2", children: [
            /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", onClick: handleSave, disabled: saving || isSubmitting, children: [
              saving ? /* @__PURE__ */ jsx("span", { className: "mr-2 h-4 w-4 animate-spin rounded-full border border-background border-t-primary" }) : null,
              labels.saveShortcut
            ] }),
            /* @__PURE__ */ jsx(
              Button,
              {
                type: "button",
                size: "sm",
                variant: "ghost",
                onClick: cancelEditing,
                disabled: saving || isSubmitting,
                children: labels.cancelShortcut
              }
            )
          ] })
        ] })
      }
    ) }) : /* @__PURE__ */ jsxs(
      "div",
      {
        className: "group/tags relative rounded-lg border bg-muted/20 p-4 transition-colors hover:border-primary/40 focus-visible:border-primary focus-visible:outline-none",
        role: disableInteraction ? void 0 : "button",
        tabIndex: disableInteraction ? -1 : 0,
        onClick: disableInteraction ? void 0 : startEditing,
        onKeyDown: (event) => {
          if (disableInteraction) return;
          if (event.key === "Enter" || event.key === " ") {
            event.preventDefault();
            void startEditing();
          }
        },
        children: [
          /* @__PURE__ */ jsx(
            "span",
            {
              "aria-hidden": "true",
              className: "pointer-events-none absolute right-3 top-3 text-muted-foreground opacity-0 transition-opacity duration-150 group-hover/tags:opacity-100 group-focus-within/tags:opacity-100",
              children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
            }
          ),
          tags.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: labels.empty }) : /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: tags.map((tag) => /* @__PURE__ */ jsx(
            "span",
            {
              className: "inline-flex items-center rounded-full border px-3 py-1 text-xs font-medium",
              style: tag.color ? { borderColor: tag.color, color: tag.color } : void 0,
              children: tag.label
            },
            tag.id
          )) })
        ]
      }
    )
  ] });
}
function TagsSection(props) {
  const handle = ComponentReplacementHandles.section("ui.detail", "TagsSection");
  const Resolved = useRegisteredComponent(
    handle,
    TagsSectionImpl
  );
  return /* @__PURE__ */ jsx("div", { "data-component-handle": handle, children: /* @__PURE__ */ jsx(Resolved, { ...props }) });
}
var TagsSection_default = TagsSection;
export {
  TagsSection,
  TagsSection_default as default
};
//# sourceMappingURL=TagsSection.js.map
