"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { AppearanceDialog } from "@open-mercato/core/modules/customers/components/detail/AppearanceDialog";
import { ArrowUpRightSquare, FileCode, Loader2, Palette, Pencil, Plus, Trash2 } from "lucide-react";
import { formatRelativeTime } from "@open-mercato/shared/lib/time";
import { Button } from "@open-mercato/ui/primitives/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue
} from "@open-mercato/ui/primitives/select";
import { flash } from "../FlashMessages.js";
import { SwitchableMarkdownInput } from "../inputs/SwitchableMarkdownInput.js";
import { ErrorMessage } from "./ErrorMessage.js";
import { LoadingMessage } from "./LoadingMessage.js";
import { TabEmptyState } from "./TabEmptyState.js";
import { useConfirmDialog } from "../confirm-dialog/index.js";
import { formatDateTime } from "@open-mercato/shared/lib/time";
import { ComponentReplacementHandles } from "@open-mercato/shared/modules/widgets/component-registry";
import { MarkdownPreview } from "../markdown/index.js";
import { useRegisteredComponent } from "../injection/useRegisteredComponent.js";
const isTestEnv = typeof process !== "undefined" && (process.env.NODE_ENV === "test" || typeof process.env.JEST_WORKER_ID !== "undefined");
let markdownPluginsPromise = null;
async function loadMarkdownPlugins() {
  if (isTestEnv) return [];
  if (!markdownPluginsPromise) {
    markdownPluginsPromise = import("remark-gfm").then((mod) => [mod.default ?? mod]).catch(() => []);
  }
  return markdownPluginsPromise;
}
function generateTempId() {
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
  return `tmp_${Math.random().toString(36).slice(2)}`;
}
function TimelineItemHeader({
  title,
  subtitle,
  timestamp,
  fallbackTimestampLabel,
  icon,
  color,
  iconSize = "md",
  className,
  renderIcon,
  renderColor
}) {
  const wrapperSize = iconSize === "sm" ? "h-6 w-6" : "h-8 w-8";
  const iconSizeClass = iconSize === "sm" ? "h-3.5 w-3.5" : "h-4 w-4";
  const resolvedTimestamp = React.useMemo(() => {
    if (subtitle) return subtitle;
    if (!timestamp) return fallbackTimestampLabel ?? null;
    const value = typeof timestamp === "string" ? timestamp : timestamp.toISOString();
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return fallbackTimestampLabel ?? null;
    const now = Date.now();
    const diff = Math.abs(now - date.getTime());
    const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
    const relativeLabel = diff <= THIRTY_DAYS_MS ? formatRelativeTime(value) : null;
    const absoluteLabel = formatDateTime(value);
    if (relativeLabel) {
      return /* @__PURE__ */ jsx("span", { title: absoluteLabel ?? void 0, children: relativeLabel });
    }
    return absoluteLabel ?? fallbackTimestampLabel ?? null;
  }, [fallbackTimestampLabel, subtitle, timestamp]);
  return /* @__PURE__ */ jsxs("div", { className: ["flex items-start gap-3", className].filter(Boolean).join(" "), children: [
    icon && renderIcon ? /* @__PURE__ */ jsx("span", { className: ["inline-flex items-center justify-center rounded border border-border bg-muted/50", wrapperSize].join(" "), children: renderIcon(icon, iconSizeClass) }) : null,
    /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
      /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
        /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-foreground", children: title }),
        color && renderColor ? renderColor(color, "h-3 w-3 rounded-full border border-border") : null
      ] }),
      resolvedTimestamp ? /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: resolvedTimestamp }) : null
    ] })
  ] });
}
function sanitizeHexColor(value) {
  if (!value) return null;
  const trimmed = value.trim();
  return /^#([0-9a-f]{6})$/i.test(trimmed) ? trimmed.toLowerCase() : null;
}
function mapCommentSummary(input) {
  const data = typeof input === "object" && input !== null ? input : {};
  const id = typeof data.id === "string" ? data.id : generateTempId();
  const body = typeof data.body === "string" ? data.body : "";
  const createdAt = typeof data.createdAt === "string" ? data.createdAt : typeof data.created_at === "string" ? data.created_at : (/* @__PURE__ */ new Date()).toISOString();
  const authorUserId = typeof data.authorUserId === "string" ? data.authorUserId : typeof data.author_user_id === "string" ? data.author_user_id : null;
  const authorName = typeof data.authorName === "string" ? data.authorName : typeof data.author_name === "string" ? data.author_name : null;
  const authorEmail = typeof data.authorEmail === "string" ? data.authorEmail : typeof data.author_email === "string" ? data.author_email : null;
  const dealId = typeof data.dealId === "string" ? data.dealId : typeof data.deal_id === "string" ? data.deal_id : null;
  const dealTitle = typeof data.dealTitle === "string" ? data.dealTitle : typeof data.deal_title === "string" ? data.deal_title : null;
  const appearanceIcon = typeof data.appearanceIcon === "string" ? data.appearanceIcon : typeof data.appearance_icon === "string" ? data.appearance_icon : null;
  const appearanceColor = typeof data.appearanceColor === "string" ? data.appearanceColor : typeof data.appearance_color === "string" ? data.appearance_color : null;
  return {
    id,
    body,
    createdAt,
    authorUserId,
    authorName,
    authorEmail,
    dealId,
    dealTitle,
    appearanceIcon,
    appearanceColor
  };
}
function NotesSectionImpl({
  entityId,
  dealId,
  emptyLabel,
  viewerUserId,
  viewerName,
  viewerEmail,
  addActionLabel,
  emptyState,
  onActionChange,
  translator,
  labelPrefix = "customers.people.detail.notes",
  inlineLabelPrefix = "customers.people.detail.inline",
  onLoadingChange,
  dealOptions,
  entityOptions,
  dataAdapter,
  dataContext,
  renderIcon,
  renderColor,
  iconSuggestions,
  readMarkdownPreference,
  writeMarkdownPreference,
  disableMarkdown
}) {
  const { confirm, ConfirmDialogElement } = useConfirmDialog();
  const t = React.useMemo(() => translator ?? ((key, fallback) => fallback ?? key), [translator]);
  const label = React.useCallback(
    (suffix, fallback, params) => t(`${labelPrefix}.${suffix}`, fallback, params),
    [labelPrefix, t]
  );
  const inlineLabel = React.useCallback(
    (suffix, fallback, params) => t(`${inlineLabelPrefix}.${suffix}`, fallback, params),
    [inlineLabelPrefix, t]
  );
  const [markdownPlugins, setMarkdownPlugins] = React.useState([]);
  React.useEffect(() => {
    if (isTestEnv) return;
    let mounted = true;
    void loadMarkdownPlugins().then((plugins) => {
      if (!mounted) return;
      setMarkdownPlugins(plugins);
    });
    return () => {
      mounted = false;
    };
  }, []);
  const normalizedDealOptions = React.useMemo(() => {
    if (!Array.isArray(dealOptions)) return [];
    const seen = /* @__PURE__ */ new Set();
    return dealOptions.map((option) => {
      if (!option || typeof option !== "object") return null;
      const id = typeof option.id === "string" ? option.id.trim() : "";
      if (!id || seen.has(id)) return null;
      const label2 = typeof option.label === "string" && option.label.trim().length ? option.label.trim() : id;
      seen.add(id);
      return { id, label: label2 };
    }).filter((option) => !!option);
  }, [dealOptions]);
  const dealLabelMap = React.useMemo(() => {
    const map = /* @__PURE__ */ new Map();
    normalizedDealOptions.forEach((option) => {
      map.set(option.id, option.label);
    });
    return map;
  }, [normalizedDealOptions]);
  const normalizedEntityOptions = React.useMemo(() => {
    if (!Array.isArray(entityOptions)) return [];
    const seen = /* @__PURE__ */ new Set();
    return entityOptions.map((option) => {
      if (!option || typeof option !== "object") return null;
      const id = typeof option.id === "string" ? option.id.trim() : "";
      if (!id || seen.has(id)) return null;
      const label2 = typeof option.label === "string" && option.label.trim().length ? option.label.trim() : id;
      seen.add(id);
      return { id, label: label2 };
    }).filter((option) => !!option);
  }, [entityOptions]);
  const [selectedDealId, setSelectedDealId] = React.useState(() => {
    const initial = typeof dealId === "string" ? dealId.trim() : "";
    return initial;
  });
  React.useEffect(() => {
    const initial = typeof dealId === "string" ? dealId.trim() : "";
    if (initial !== selectedDealId) {
      setSelectedDealId(initial);
    }
  }, [dealId, selectedDealId]);
  const [selectedEntityId, setSelectedEntityId] = React.useState(() => {
    if (normalizedEntityOptions.length) return normalizedEntityOptions[0].id;
    return typeof entityId === "string" ? entityId : "";
  });
  React.useEffect(() => {
    if (normalizedEntityOptions.length) {
      if (!normalizedEntityOptions.some((option) => option.id === selectedEntityId)) {
        setSelectedEntityId(normalizedEntityOptions[0].id);
      }
    } else {
      const initial = typeof entityId === "string" ? entityId : "";
      if (initial !== selectedEntityId) {
        setSelectedEntityId(initial);
      }
    }
  }, [entityId, normalizedEntityOptions, selectedEntityId]);
  const resolvedEntityId = React.useMemo(() => {
    if (normalizedEntityOptions.length) return selectedEntityId;
    return typeof entityId === "string" ? entityId : "";
  }, [entityId, normalizedEntityOptions, selectedEntityId]);
  const resolvedDealId = React.useMemo(() => {
    const trimmed = typeof selectedDealId === "string" ? selectedDealId.trim() : "";
    return trimmed;
  }, [selectedDealId]);
  const hasEntity = resolvedEntityId.length > 0;
  const [notes, setNotes] = React.useState([]);
  const [isLoading, setIsLoading] = React.useState(() => Boolean(entityId || dealId));
  const [isSubmitting, setIsSubmitting] = React.useState(false);
  const [loadError, setLoadError] = React.useState(null);
  const pendingCounterRef = React.useRef(0);
  const pushLoading = React.useCallback(() => {
    pendingCounterRef.current += 1;
    if (pendingCounterRef.current === 1) {
      onLoadingChange?.(true);
    }
  }, [onLoadingChange]);
  const popLoading = React.useCallback(() => {
    pendingCounterRef.current = Math.max(0, pendingCounterRef.current - 1);
    if (pendingCounterRef.current === 0) {
      onLoadingChange?.(false);
    }
  }, [onLoadingChange]);
  const [composerOpen, setComposerOpen] = React.useState(false);
  const [draftBody, setDraftBody] = React.useState("");
  const [draftIcon, setDraftIcon] = React.useState(null);
  const [draftColor, setDraftColor] = React.useState(null);
  const [isMarkdownEnabled, setIsMarkdownEnabled] = React.useState(false);
  const textareaRef = React.useRef(null);
  const formRef = React.useRef(null);
  const focusComposer = React.useCallback(() => {
    if (!hasEntity) return;
    setComposerOpen(true);
    window.requestAnimationFrame(() => {
      if (isMarkdownEnabled) {
        const markdownTextarea = formRef.current?.querySelector("textarea");
        if (markdownTextarea instanceof HTMLTextAreaElement) {
          markdownTextarea.focus();
          markdownTextarea.scrollIntoView({ behavior: "smooth", block: "center" });
          return;
        }
      }
      const element = textareaRef.current;
      if (!element) return;
      element.focus();
      element.scrollIntoView({ behavior: "smooth", block: "center" });
    });
  }, [formRef, hasEntity, isMarkdownEnabled]);
  const [appearanceDialogState, setAppearanceDialogState] = React.useState(null);
  const [appearanceDialogSaving, setAppearanceDialogSaving] = React.useState(false);
  const [appearanceDialogError, setAppearanceDialogError] = React.useState(null);
  const [contentEditor, setContentEditor] = React.useState({ id: "", value: "" });
  const [contentSavingId, setContentSavingId] = React.useState(null);
  const [contentError, setContentError] = React.useState(null);
  const contentTextareaRef = React.useRef(null);
  const [visibleCount, setVisibleCount] = React.useState(0);
  const [currentPage, setCurrentPage] = React.useState(1);
  const [totalPages, setTotalPages] = React.useState(1);
  const [deletingNoteId, setDeletingNoteId] = React.useState(null);
  const pagedMode = typeof dataAdapter.listPage === "function";
  React.useEffect(() => {
    const queryEntityId = typeof entityId === "string" ? entityId : "";
    const queryDealId = typeof dealId === "string" ? dealId : "";
    if (!queryEntityId && !queryDealId) {
      setNotes([]);
      setLoadError(null);
      setIsLoading(false);
      setCurrentPage(1);
      setTotalPages(1);
      return;
    }
    let cancelled = false;
    setIsLoading(true);
    setLoadError(null);
    pushLoading();
    async function loadNotes() {
      try {
        if (dataAdapter.listPage) {
          const pageResult = await dataAdapter.listPage({
            entityId: queryEntityId || null,
            dealId: queryDealId || null,
            page: 1,
            pageSize: 20,
            context: dataContext
          });
          if (cancelled) return;
          setNotes(pageResult.items);
          setCurrentPage(pageResult.page);
          setTotalPages(pageResult.totalPages);
          return;
        }
        const mapped = await dataAdapter.list({
          entityId: queryEntityId || null,
          dealId: queryDealId || null,
          context: dataContext
        });
        if (cancelled) return;
        setNotes(mapped);
        setCurrentPage(1);
        setTotalPages(1);
      } catch (err) {
        if (cancelled) return;
        const message = err instanceof Error ? err.message : label("loadError", "Failed to load notes.");
        setNotes([]);
        setLoadError(message);
        setCurrentPage(1);
        setTotalPages(1);
        flash(message, "error");
      } finally {
        if (!cancelled) setIsLoading(false);
        popLoading();
      }
    }
    loadNotes().catch(() => {
    });
    return () => {
      cancelled = true;
    };
  }, [dataAdapter, dataContext, dealId, entityId, label, popLoading, pushLoading]);
  const youLabel = label("you", "You");
  const viewerLabel = React.useMemo(() => viewerName ?? viewerEmail ?? null, [viewerEmail, viewerName]);
  const handleMarkdownToggle = React.useCallback(() => {
    setIsMarkdownEnabled((prev) => {
      const next = !prev;
      if (writeMarkdownPreference) {
        writeMarkdownPreference(next);
      }
      return next;
    });
  }, [writeMarkdownPreference]);
  React.useEffect(() => {
    if (!onActionChange) return;
    if (!notes.length) {
      onActionChange(null);
      return;
    }
    onActionChange({
      label: addActionLabel,
      onClick: focusComposer,
      disabled: isSubmitting || isLoading || !hasEntity,
      icon: /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" })
    });
    return () => onActionChange(null);
  }, [onActionChange, addActionLabel, focusComposer, hasEntity, isLoading, isSubmitting, notes.length]);
  const adjustTextareaSize = React.useCallback((element) => {
    if (!element) return;
    element.style.height = "auto";
    element.style.height = `${element.scrollHeight}px`;
  }, []);
  React.useEffect(() => {
    adjustTextareaSize(textareaRef.current);
  }, [adjustTextareaSize, draftBody, isMarkdownEnabled, composerOpen]);
  React.useEffect(() => {
    const preference = readMarkdownPreference ? readMarkdownPreference() : null;
    if (preference !== null) {
      setIsMarkdownEnabled(preference);
    }
  }, [readMarkdownPreference]);
  React.useEffect(() => {
    if (pagedMode) {
      setVisibleCount(notes.length);
      return;
    }
    if (!notes.length) {
      setVisibleCount(0);
      return;
    }
    const baseline = Math.min(5, notes.length);
    setVisibleCount((prev) => {
      if (prev >= notes.length) return prev;
      return Math.min(Math.max(prev, baseline), notes.length);
    });
  }, [notes.length, pagedMode]);
  React.useEffect(() => {
    if (hasEntity) return;
    setComposerOpen(false);
    setDraftBody("");
    setDraftIcon(null);
    setDraftColor(null);
  }, [hasEntity]);
  const visibleNotes = React.useMemo(
    () => pagedMode ? notes : notes.slice(0, visibleCount),
    [notes, pagedMode, visibleCount]
  );
  const hasVisibleNotes = React.useMemo(
    () => pagedMode ? notes.length > 0 : visibleCount > 0,
    [notes.length, pagedMode, visibleCount]
  );
  const loadMoreLabel = label("loadMore");
  const handleCreateNote = React.useCallback(
    async (input) => {
      if (!hasEntity || !resolvedEntityId) {
        flash(label("entityMissing", "Unable to determine current person."), "error");
        return false;
      }
      const body = input.body.trim();
      const strippedBody = body.replace(/^[\s#\-*>_~`|+\\\n\r]+$/gm, "").replace(/\s+/g, "");
      if (!body || !strippedBody.length) {
        focusComposer();
        return false;
      }
      const icon = input.appearanceIcon && input.appearanceIcon.trim().length ? input.appearanceIcon.trim() : null;
      const color = sanitizeHexColor(input.appearanceColor);
      const targetDealId = resolvedDealId.length ? resolvedDealId : null;
      const dealLabel = targetDealId ? dealLabelMap.get(targetDealId) ?? null : null;
      setIsSubmitting(true);
      pushLoading();
      try {
        const responseBody = await dataAdapter.create({
          entityId: resolvedEntityId,
          body,
          appearanceIcon: icon,
          appearanceColor: color,
          dealId: targetDealId,
          context: dataContext
        }) ?? {};
        setNotes((prev) => {
          const viewerId = viewerUserId ?? null;
          const resolvedAuthorId = typeof responseBody?.authorUserId === "string" ? responseBody.authorUserId : viewerId ?? null;
          const resolvedAuthorName = (() => {
            if (resolvedAuthorId && viewerId && resolvedAuthorId === viewerId) {
              return youLabel;
            }
            return typeof responseBody?.authorName === "string" ? responseBody.authorName : viewerLabel;
          })();
          const resolvedAuthorEmail = (() => {
            if (resolvedAuthorId && viewerId && resolvedAuthorId === viewerId) {
              return viewerEmail ?? null;
            }
            return typeof responseBody?.authorEmail === "string" ? responseBody.authorEmail : null;
          })();
          const newNote = {
            id: typeof responseBody?.id === "string" ? responseBody.id : generateTempId(),
            body,
            createdAt: (/* @__PURE__ */ new Date()).toISOString(),
            authorUserId: resolvedAuthorId,
            authorName: resolvedAuthorName,
            authorEmail: resolvedAuthorEmail,
            dealId: targetDealId,
            dealTitle: dealLabel,
            appearanceIcon: icon,
            appearanceColor: color
          };
          return [newNote, ...prev];
        });
        setVisibleCount((prev) => Math.max(prev, 1));
        flash(label("success"), "success");
        return true;
      } catch (err) {
        const message = err instanceof Error ? err.message : label("error");
        flash(message, "error");
        return false;
      } finally {
        setIsSubmitting(false);
        popLoading();
      }
    },
    [dataAdapter, dataContext, dealLabelMap, focusComposer, hasEntity, popLoading, pushLoading, resolvedDealId, resolvedEntityId, t, viewerEmail, viewerLabel, viewerUserId, youLabel]
  );
  const handleUpdateNote = React.useCallback(
    async (noteId, patch) => {
      const sanitizedBody = patch.body;
      const sanitizedIcon = patch.appearanceIcon !== void 0 && patch.appearanceIcon !== null && patch.appearanceIcon.trim().length ? patch.appearanceIcon.trim() : patch.appearanceIcon === null ? null : void 0;
      const sanitizedColor = patch.appearanceColor !== void 0 ? sanitizeHexColor(patch.appearanceColor ?? null) : void 0;
      try {
        await dataAdapter.update({
          id: noteId,
          patch: {
            body: sanitizedBody,
            appearanceIcon: sanitizedIcon,
            appearanceColor: sanitizedColor
          },
          context: dataContext
        });
        setNotes((prev) => {
          const nextComments = prev.map((comment) => {
            if (comment.id !== noteId) return comment;
            const next = { ...comment };
            if (sanitizedBody !== void 0) next.body = sanitizedBody;
            if (sanitizedIcon !== void 0) next.appearanceIcon = sanitizedIcon ?? null;
            if (sanitizedColor !== void 0) next.appearanceColor = sanitizedColor ?? null;
            return next;
          });
          return nextComments;
        });
        flash(label("updateSuccess"), "success");
      } catch (error) {
        const message = error instanceof Error ? error.message : label("updateError");
        flash(message, "error");
        throw error instanceof Error ? error : new Error(message);
      }
    },
    [dataAdapter, dataContext, t]
  );
  const handleDeleteNote = React.useCallback(
    async (note) => {
      const confirmed = await confirm({
        title: label("deleteConfirm", "Delete this note? You can restore it using version history."),
        variant: "destructive"
      });
      if (!confirmed) return;
      setDeletingNoteId(note.id);
      pushLoading();
      try {
        await dataAdapter.delete({ id: note.id, context: dataContext });
        setNotes((prev) => prev.filter((existing) => existing.id !== note.id));
        if (pagedMode) {
          setVisibleCount((prev) => Math.max(0, prev - 1));
        }
        flash(label("deleteSuccess", "Note deleted"), "success");
      } catch (err) {
        const message = err instanceof Error ? err.message : label("deleteError", "Failed to delete note");
        flash(message, "error");
      } finally {
        setDeletingNoteId(null);
        popLoading();
      }
    },
    [confirm, dataAdapter, dataContext, label, popLoading, pushLoading]
  );
  const handleSubmit = React.useCallback(
    async (event) => {
      event.preventDefault();
      const created = await handleCreateNote({
        body: draftBody,
        appearanceIcon: draftIcon,
        appearanceColor: draftColor
      });
      if (created) {
        setDraftBody("");
        setDraftIcon(null);
        setDraftColor(null);
      }
    },
    [draftBody, draftColor, draftIcon, handleCreateNote]
  );
  const handleLoadMore = React.useCallback(() => {
    if (pagedMode && dataAdapter.listPage) {
      if (currentPage >= totalPages || isLoading) return;
      const queryEntityId = typeof entityId === "string" ? entityId : "";
      const queryDealId = typeof dealId === "string" ? dealId : "";
      setIsLoading(true);
      pushLoading();
      void dataAdapter.listPage({
        entityId: queryEntityId || null,
        dealId: queryDealId || null,
        page: currentPage + 1,
        pageSize: 20,
        context: dataContext
      }).then((pageResult) => {
        setNotes((prev) => [...prev, ...pageResult.items]);
        setCurrentPage(pageResult.page);
        setTotalPages(pageResult.totalPages);
      }).catch((error) => {
        const message = error instanceof Error ? error.message : label("loadError", "Failed to load notes.");
        flash(message, "error");
      }).finally(() => {
        setIsLoading(false);
        popLoading();
      });
      return;
    }
    setVisibleCount((prev) => {
      if (prev >= notes.length) return prev;
      return Math.min(prev + 5, notes.length);
    });
  }, [currentPage, dataAdapter, dataContext, dealId, entityId, flash, isLoading, label, notes.length, pagedMode, popLoading, pushLoading, totalPages]);
  const handleAppearanceDialogSubmit = React.useCallback(async () => {
    if (!appearanceDialogState) return;
    setAppearanceDialogError(null);
    const sanitizedIcon = appearanceDialogState.icon && appearanceDialogState.icon.trim().length ? appearanceDialogState.icon.trim() : null;
    const sanitizedColor = sanitizeHexColor(appearanceDialogState.color ?? null);
    if (appearanceDialogState.mode === "create") {
      setDraftIcon(sanitizedIcon);
      setDraftColor(sanitizedColor);
      setAppearanceDialogState(null);
      return;
    }
    setAppearanceDialogSaving(true);
    try {
      await handleUpdateNote(appearanceDialogState.noteId, {
        appearanceIcon: sanitizedIcon,
        appearanceColor: sanitizedColor
      });
      setAppearanceDialogState(null);
    } catch (err) {
      const message = err instanceof Error ? err.message : label("appearance.error", "Failed to update appearance.");
      setAppearanceDialogError(message);
    } finally {
      setAppearanceDialogSaving(false);
    }
  }, [appearanceDialogState, handleUpdateNote, t]);
  const handleAppearanceDialogClose = React.useCallback(() => {
    if (appearanceDialogSaving) return;
    setAppearanceDialogState(null);
    setAppearanceDialogError(null);
  }, [appearanceDialogSaving]);
  const handleContentSave = React.useCallback(async () => {
    if (!contentEditor.id) return;
    const trimmed = contentEditor.value.trim();
    if (!trimmed) {
      setContentError(label("updateError", "Failed to update note"));
      return;
    }
    setContentSavingId(contentEditor.id);
    setContentError(null);
    try {
      await handleUpdateNote(contentEditor.id, { body: trimmed });
      setContentEditor({ id: "", value: "" });
    } catch (err) {
      const message = err instanceof Error ? err.message : label("updateError", "Failed to update note");
      setContentError(message);
    } finally {
      setContentSavingId(null);
    }
  }, [contentEditor, handleUpdateNote, t]);
  const handleContentEditorKeyDown = React.useCallback(
    (event) => {
      if (!contentEditor.id) return;
      if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
        event.preventDefault();
        if (!contentSavingId) void handleContentSave();
        return;
      }
      if (event.key === "Escape") {
        event.preventDefault();
        setContentEditor({ id: "", value: "" });
        setContentError(null);
      }
    },
    [contentEditor.id, contentSavingId, handleContentSave]
  );
  const handleComposerKeyDown = React.useCallback(
    (event) => {
      if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
        event.preventDefault();
        formRef.current?.requestSubmit();
      }
    },
    []
  );
  const handleContentKeyDown = React.useCallback(
    (event, note) => {
      if (event.key === "Enter" || event.key === " ") {
        event.preventDefault();
        setContentEditor({ id: note.id, value: note.body });
      }
    },
    []
  );
  const noteAuthorLabel = React.useCallback(
    (note) => {
      if (note.authorUserId && viewerUserId && note.authorUserId === viewerUserId) {
        return youLabel;
      }
      return note.authorName ?? note.authorEmail ?? youLabel;
    },
    [viewerUserId, youLabel]
  );
  const noteAppearanceLabels = React.useMemo(
    () => ({
      colorLabel: label("appearance.colorLabel"),
      colorHelp: label("appearance.colorHelp"),
      colorClearLabel: label("appearance.clearColor"),
      iconLabel: label("appearance.iconLabel"),
      iconPlaceholder: label("appearance.iconPlaceholder"),
      iconPickerTriggerLabel: label("appearance.iconPicker"),
      iconSearchPlaceholder: label("appearance.iconSearchPlaceholder"),
      iconSearchEmptyLabel: label("appearance.iconSearchEmpty"),
      iconSuggestionsLabel: label("appearance.iconSuggestions"),
      iconClearLabel: label("appearance.iconClear"),
      previewEmptyLabel: label("appearance.previewEmpty")
    }),
    [label]
  );
  const composerAuthor = React.useMemo(
    () => youLabel,
    [youLabel]
  );
  const composerHasAppearance = Boolean(draftIcon) || Boolean(draftColor);
  const appearanceDialogOpen = appearanceDialogState !== null;
  const editingAppearanceNoteId = appearanceDialogState?.mode === "edit" ? appearanceDialogState.noteId : null;
  const addNoteShortcutLabel = label("addShortcut", "Add note \u2318\u23CE / Ctrl+Enter");
  const saveAppearanceShortcutLabel = label("appearance.saveShortcut", "Save appearance \u2318\u23CE / Ctrl+Enter");
  const composerSubmitLabel = addNoteShortcutLabel;
  const appearanceDialogPrimaryLabel = saveAppearanceShortcutLabel;
  const appearanceDialogSavingLabel = appearanceDialogState?.mode === "edit" ? label("appearance.saving") : label("saving", "Saving note\u2026");
  return /* @__PURE__ */ jsxs("div", { className: "mt-0 space-y-2", children: [
    /* @__PURE__ */ jsx(
      "div",
      {
        className: [
          "overflow-hidden rounded-xl transition-all duration-300 ease-out",
          composerOpen ? "max-h-[1200px] bg-muted/30 p-4 opacity-100" : "pointer-events-none max-h-0 p-0 opacity-0"
        ].join(" "),
        "aria-hidden": !composerOpen,
        children: composerOpen ? /* @__PURE__ */ jsxs(
          "form",
          {
            ref: formRef,
            onSubmit: handleSubmit,
            onKeyDown: handleComposerKeyDown,
            className: "space-y-3",
            children: [
              /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
                /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: label("addLabel") }),
                /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1", children: [
                  /* @__PURE__ */ jsxs(
                    Button,
                    {
                      type: "button",
                      variant: "ghost",
                      size: "icon",
                      onClick: () => {
                        setAppearanceDialogError(null);
                        setAppearanceDialogState({ mode: "create", icon: draftIcon, color: draftColor });
                      },
                      disabled: isSubmitting || isLoading || !hasEntity,
                      children: [
                        /* @__PURE__ */ jsx("span", { className: "sr-only", children: label("appearance.toggleOpen", "Customize appearance") }),
                        /* @__PURE__ */ jsx(Palette, { className: "h-4 w-4" })
                      ]
                    }
                  ),
                  disableMarkdown ? null : /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      variant: isMarkdownEnabled ? "secondary" : "ghost",
                      size: "icon",
                      onClick: handleMarkdownToggle,
                      "aria-pressed": isMarkdownEnabled,
                      disabled: isSubmitting || isLoading,
                      children: /* @__PURE__ */ jsx(FileCode, { className: "h-4 w-4" })
                    }
                  ),
                  /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      size: "sm",
                      variant: "ghost",
                      onClick: () => {
                        setComposerOpen(false);
                        setDraftBody("");
                        setDraftIcon(null);
                        setDraftColor(null);
                      },
                      disabled: isSubmitting || isLoading,
                      children: inlineLabel("cancel")
                    }
                  )
                ] })
              ] }),
              normalizedEntityOptions.length || normalizedDealOptions.length ? /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
                normalizedEntityOptions.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
                  /* @__PURE__ */ jsx(
                    "label",
                    {
                      htmlFor: "note-entity-select",
                      className: "text-xs font-medium text-muted-foreground",
                      children: label("fields.entity", "Assign to customer")
                    }
                  ),
                  /* @__PURE__ */ jsxs(
                    Select,
                    {
                      value: selectedEntityId || void 0,
                      onValueChange: (next) => setSelectedEntityId(next ?? ""),
                      disabled: isSubmitting || isLoading || !normalizedEntityOptions.length,
                      children: [
                        /* @__PURE__ */ jsx(SelectTrigger, { id: "note-entity-select", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
                        /* @__PURE__ */ jsx(SelectContent, { children: normalizedEntityOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.id, children: option.label }, option.id)) })
                      ]
                    }
                  )
                ] }) : null,
                normalizedDealOptions.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
                  /* @__PURE__ */ jsx(
                    "label",
                    {
                      htmlFor: "note-deal-select",
                      className: "text-xs font-medium text-muted-foreground",
                      children: label("fields.deal", "Link to deal (optional)")
                    }
                  ),
                  /* @__PURE__ */ jsxs(
                    Select,
                    {
                      value: selectedDealId || void 0,
                      onValueChange: (next) => setSelectedDealId(next ?? ""),
                      disabled: isSubmitting || isLoading,
                      children: [
                        /* @__PURE__ */ jsx(SelectTrigger, { id: "note-deal-select", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: label("fields.dealPlaceholder", "No linked deal") }) }),
                        /* @__PURE__ */ jsx(SelectContent, { children: normalizedDealOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.id, children: option.label }, option.id)) })
                      ]
                    }
                  )
                ] }) : null
              ] }) : null,
              /* @__PURE__ */ jsx(
                SwitchableMarkdownInput,
                {
                  value: draftBody,
                  onChange: setDraftBody,
                  isMarkdownEnabled,
                  disableMarkdown,
                  rows: 1,
                  placeholder: label("placeholder"),
                  textareaRef,
                  onTextareaInput: (event) => adjustTextareaSize(event.currentTarget),
                  disabled: isSubmitting || isLoading || !hasEntity,
                  remarkPlugins: markdownPlugins
                }
              ),
              composerHasAppearance ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-lg border border-dashed border-muted-foreground/40 px-3 py-2", children: [
                /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 text-sm", children: [
                  draftIcon && renderIcon ? /* @__PURE__ */ jsx("span", { className: "inline-flex h-7 w-7 items-center justify-center rounded border border-border bg-muted/50", children: renderIcon(draftIcon, "h-4 w-4") }) : null,
                  /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: composerAuthor }),
                  draftColor && renderColor ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
                    renderColor(draftColor, "h-3.5 w-3.5 rounded-full border border-border"),
                    /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase text-muted-foreground", children: draftColor })
                  ] }) : null
                ] }),
                /* @__PURE__ */ jsx(
                  Button,
                  {
                    type: "button",
                    size: "sm",
                    variant: "ghost",
                    onClick: () => {
                      setDraftIcon(null);
                      setDraftColor(null);
                    },
                    disabled: isSubmitting,
                    children: label("appearance.clearAll", "Clear")
                  }
                )
              ] }) : null,
              /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
                Button,
                {
                  type: "submit",
                  size: "sm",
                  disabled: isSubmitting || isLoading || !hasEntity,
                  children: [
                    isSubmitting ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
                    composerSubmitLabel
                  ]
                }
              ) })
            ]
          }
        ) : null
      }
    ),
    loadError ? /* @__PURE__ */ jsx(ErrorMessage, { label: loadError, className: "mt-3" }) : null,
    /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
      !composerOpen && hasVisibleNotes && !onActionChange ? /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
        Button,
        {
          type: "button",
          variant: "outline",
          size: "sm",
          onClick: focusComposer,
          disabled: isSubmitting || isLoading || !hasEntity,
          children: [
            /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
            addActionLabel
          ]
        }
      ) }) : null,
      isLoading ? /* @__PURE__ */ jsx(
        LoadingMessage,
        {
          label: label("loading", "Loading notes\u2026"),
          className: "border-0 bg-transparent p-0 py-8 justify-center"
        }
      ) : hasVisibleNotes ? visibleNotes.map((note) => {
        const author = noteAuthorLabel(note);
        const isAppearanceSaving = appearanceDialogSaving && editingAppearanceNoteId === note.id;
        const isEditingContent = contentEditor.id === note.id;
        const displayIcon = note.appearanceIcon ?? null;
        const displayColor = note.appearanceColor ?? null;
        const timestampValue = note.createdAt;
        const fallbackTimestampLabel = formatDateTime(note.createdAt) ?? emptyLabel;
        return /* @__PURE__ */ jsxs("div", { className: "group space-y-2 rounded-lg border bg-card p-4", children: [
          /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
            /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
              /* @__PURE__ */ jsx(
                TimelineItemHeader,
                {
                  title: author,
                  timestamp: timestampValue,
                  fallbackTimestampLabel,
                  icon: displayIcon,
                  color: displayColor,
                  renderIcon,
                  renderColor
                }
              ),
              note.dealId ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
                /* @__PURE__ */ jsx(ArrowUpRightSquare, { className: "h-3.5 w-3.5" }),
                /* @__PURE__ */ jsx(
                  "a",
                  {
                    href: `/backend/customers/deals/${encodeURIComponent(note.dealId)}`,
                    className: "font-medium text-foreground hover:underline",
                    children: note.dealTitle && note.dealTitle.length ? note.dealTitle : label("linkedDeal", "Linked deal")
                  }
                )
              ] }) : null
            ] }),
            /* @__PURE__ */ jsxs(
              "div",
              {
                className: `flex items-center gap-2 transition-opacity ${isEditingContent ? "opacity-100" : "opacity-100 md:opacity-0 md:group-hover:opacity-100 focus-within:opacity-100"}`,
                children: [
                  /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      variant: "ghost",
                      size: "icon",
                      onClick: () => setContentEditor({ id: note.id, value: note.body }),
                      children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
                    }
                  ),
                  /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      variant: "ghost",
                      size: "icon",
                      onClick: (event) => {
                        event.stopPropagation();
                        setAppearanceDialogError(null);
                        setAppearanceDialogState({
                          mode: "edit",
                          noteId: note.id,
                          icon: note.appearanceIcon ?? null,
                          color: note.appearanceColor ?? null
                        });
                      },
                      disabled: appearanceDialogSaving && editingAppearanceNoteId === note.id,
                      children: isAppearanceSaving ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Palette, { className: "h-4 w-4" })
                    }
                  ),
                  /* @__PURE__ */ jsx(
                    Button,
                    {
                      type: "button",
                      variant: "ghost",
                      size: "icon",
                      onClick: (event) => {
                        event.stopPropagation();
                        void handleDeleteNote(note);
                      },
                      disabled: deletingNoteId === note.id,
                      children: deletingNoteId === note.id ? /* @__PURE__ */ jsx("span", { className: "relative flex h-4 w-4 items-center justify-center text-destructive", children: /* @__PURE__ */ jsx("span", { className: "absolute h-4 w-4 animate-spin rounded-full border border-destructive border-t-transparent" }) }) : /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
                    }
                  )
                ]
              }
            )
          ] }),
          isEditingContent ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", onKeyDown: handleContentEditorKeyDown, children: [
            /* @__PURE__ */ jsx(
              SwitchableMarkdownInput,
              {
                value: contentEditor.value,
                onChange: (nextValue) => setContentEditor((prev) => ({ ...prev, value: nextValue })),
                isMarkdownEnabled,
                disableMarkdown,
                rows: 3,
                textareaRef: contentTextareaRef,
                onTextareaInput: (event) => adjustTextareaSize(event.currentTarget),
                textareaClassName: "w-full resize-none overflow-hidden rounded-md border border-border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
                editorWrapperClassName: "w-full rounded-md border border-muted-foreground/20 bg-background p-2",
                remarkPlugins: markdownPlugins
              }
            ),
            contentError ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: contentError }) : null,
            /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
              /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: handleContentSave, disabled: contentSavingId === note.id, children: contentSavingId === note.id ? /* @__PURE__ */ jsxs(Fragment, { children: [
                /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
                label("saving")
              ] }) : inlineLabel("saveShortcut") }),
              disableMarkdown ? null : /* @__PURE__ */ jsx(
                Button,
                {
                  type: "button",
                  variant: "ghost",
                  size: "icon",
                  onClick: handleMarkdownToggle,
                  "aria-pressed": isMarkdownEnabled,
                  className: isMarkdownEnabled ? "text-primary" : void 0,
                  disabled: contentSavingId === note.id,
                  children: /* @__PURE__ */ jsx(FileCode, { className: "h-4 w-4" })
                }
              ),
              /* @__PURE__ */ jsx(
                Button,
                {
                  type: "button",
                  size: "sm",
                  variant: "ghost",
                  onClick: () => setContentEditor({ id: "", value: "" }),
                  disabled: contentSavingId === note.id,
                  children: inlineLabel("cancel")
                }
              )
            ] })
          ] }) : /* @__PURE__ */ jsx(
            "div",
            {
              role: "button",
              tabIndex: 0,
              className: "cursor-pointer text-sm",
              onClick: () => setContentEditor({ id: note.id, value: note.body }),
              onKeyDown: (event) => handleContentKeyDown(event, note),
              children: /* @__PURE__ */ jsx(
                MarkdownPreview,
                {
                  remarkPlugins: markdownPlugins,
                  className: "break-words text-foreground [&>*]:mb-2 [&>*:last-child]:mb-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs",
                  children: note.body
                }
              )
            }
          )
        ] }, note.id);
      }) : composerOpen ? null : /* @__PURE__ */ jsx(
        TabEmptyState,
        {
          title: emptyState.title,
          description: emptyState.description,
          action: {
            label: emptyState.actionLabel,
            onClick: focusComposer,
            disabled: isSubmitting || !hasEntity
          }
        }
      ),
      isLoading || (pagedMode ? currentPage >= totalPages : visibleCount >= notes.length) ? null : /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleLoadMore, children: loadMoreLabel }) })
    ] }),
    /* @__PURE__ */ jsx(
      AppearanceDialog,
      {
        open: appearanceDialogOpen,
        title: appearanceDialogState?.mode === "edit" ? label("appearance.edit") : label("appearance.toggleOpen", "Customize appearance"),
        icon: appearanceDialogState?.icon ?? null,
        color: appearanceDialogState?.color ?? null,
        labels: noteAppearanceLabels,
        iconSuggestions,
        onIconChange: (value) => setAppearanceDialogState((prev) => prev ? { ...prev, icon: value ?? null } : prev),
        onColorChange: (value) => setAppearanceDialogState((prev) => prev ? { ...prev, color: value ?? null } : prev),
        onSubmit: () => {
          void handleAppearanceDialogSubmit();
        },
        onClose: handleAppearanceDialogClose,
        isSaving: appearanceDialogSaving,
        errorMessage: appearanceDialogError,
        primaryLabel: appearanceDialogPrimaryLabel,
        savingLabel: appearanceDialogSavingLabel,
        cancelLabel: label("appearance.cancel")
      }
    ),
    ConfirmDialogElement
  ] });
}
function NotesSection(props) {
  const handle = ComponentReplacementHandles.section("ui.detail", "NotesSection");
  const Resolved = useRegisteredComponent(
    handle,
    NotesSectionImpl
  );
  return /* @__PURE__ */ jsx("div", { "data-component-handle": handle, children: /* @__PURE__ */ jsx(Resolved, { ...props }) });
}
export {
  NotesSection,
  mapCommentSummary,
  sanitizeHexColor
};
//# sourceMappingURL=NotesSection.js.map
