"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// packages/editor/src/components/collab-sidebar/hooks.js
var hooks_exports = {};
__export(hooks_exports, {
  useEnableFloatingSidebar: () => useEnableFloatingSidebar,
  useFloatingBoard: () => useFloatingBoard,
  useNoteActions: () => useNoteActions,
  useNoteThreads: () => useNoteThreads
});
module.exports = __toCommonJS(hooks_exports);
var import_i18n = require("@wordpress/i18n");
var import_element = require("@wordpress/element");
var import_core_data = require("@wordpress/core-data");
var import_data = require("@wordpress/data");
var import_block_editor = require("@wordpress/block-editor");
var import_notices = require("@wordpress/notices");
var import_dom = require("@wordpress/dom");
var import_html_entities = require("@wordpress/html-entities");
var import_interface = require("@wordpress/interface");
var import_store = require("../../store/index.cjs");
var import_constants = require("./constants.cjs");
var import_lock_unlock = require("../../lock-unlock.cjs");
var import_board_store = require("./board-store.cjs");
var import_utils = require("./utils.cjs");
var { cleanEmptyObject } = (0, import_lock_unlock.unlock)(import_block_editor.privateApis);
function useNoteThreads(postId) {
  const queryArgs = {
    post: postId,
    type: "note",
    status: "all",
    per_page: -1
  };
  const { records: threads } = (0, import_core_data.useEntityRecords)(
    "root",
    "comment",
    queryArgs,
    { enabled: !!postId && typeof postId === "number" }
  );
  const { getBlockAttributes } = (0, import_data.useSelect)(import_block_editor.store);
  const { clientIds } = (0, import_data.useSelect)((select) => {
    const { getClientIdsWithDescendants } = select(import_block_editor.store);
    return {
      clientIds: getClientIdsWithDescendants()
    };
  }, []);
  const { notes, unresolvedNotes } = (0, import_element.useMemo)(() => {
    if (!threads || threads.length === 0) {
      return { notes: [], unresolvedNotes: [] };
    }
    const blocksWithNotes = {};
    const clientIdByNoteId = /* @__PURE__ */ new Map();
    for (const clientId of clientIds) {
      const noteId = getBlockAttributes(clientId)?.metadata?.noteId;
      if (noteId) {
        const key = String(noteId);
        blocksWithNotes[clientId] = key;
        clientIdByNoteId.set(key, clientId);
      }
    }
    const threadsById = /* @__PURE__ */ new Map();
    const rootThreads = [];
    for (const item of threads) {
      const thread = {
        ...item,
        reply: [],
        blockClientId: item.parent === 0 ? clientIdByNoteId.get(String(item.id)) ?? null : null
      };
      threadsById.set(item.id, thread);
      if (item.parent === 0) {
        rootThreads.push(thread);
      }
    }
    for (const item of threads) {
      if (item.parent !== 0) {
        threadsById.get(item.parent)?.reply.unshift(threadsById.get(item.id));
      }
    }
    if (rootThreads.length === 0) {
      return { notes: [], unresolvedNotes: [] };
    }
    const unresolved = [];
    const resolved = [];
    for (const noteId of Object.values(blocksWithNotes)) {
      const thread = threadsById.get(Number(noteId)) ?? threadsById.get(noteId);
      if (!thread) {
        continue;
      }
      if (thread.status === "hold") {
        unresolved.push(thread);
      } else if (thread.status === "approved") {
        resolved.push(thread);
      }
    }
    const orphans = rootThreads.filter(
      (thread) => !thread.blockClientId
    );
    return {
      notes: [...unresolved, ...resolved, ...orphans],
      unresolvedNotes: unresolved
    };
  }, [clientIds, threads, getBlockAttributes]);
  return {
    notes,
    unresolvedNotes
  };
}
function useNoteActions() {
  const { createNotice } = (0, import_data.useDispatch)(import_notices.store);
  const { saveEntityRecord, deleteEntityRecord } = (0, import_data.useDispatch)(import_core_data.store);
  const { getCurrentPostId } = (0, import_data.useSelect)(import_store.store);
  const { getBlockAttributes, getSelectedBlockClientId } = (0, import_data.useSelect)(import_block_editor.store);
  const { updateBlockAttributes } = (0, import_data.useDispatch)(import_block_editor.store);
  const onError = (error) => {
    const errorMessage = error.message && error.code !== "unknown_error" ? (0, import_html_entities.decodeEntities)(error.message) : (0, import_i18n.__)("An error occurred while performing an update.");
    createNotice("error", errorMessage, {
      type: "snackbar",
      isDismissible: true
    });
  };
  const onCreate = async ({ content, parent }) => {
    try {
      const savedRecord = await saveEntityRecord(
        "root",
        "comment",
        {
          post: getCurrentPostId(),
          content,
          status: "hold",
          type: "note",
          parent: parent || 0
        },
        { throwOnError: true }
      );
      if (!parent && savedRecord?.id) {
        const clientId = getSelectedBlockClientId();
        const metadata = getBlockAttributes(clientId)?.metadata;
        updateBlockAttributes(clientId, {
          metadata: {
            ...metadata,
            noteId: savedRecord.id
          }
        });
      }
      createNotice(
        "snackbar",
        parent ? (0, import_i18n.__)("Reply added.") : (0, import_i18n.__)("Note added."),
        {
          type: "snackbar",
          isDismissible: true
        }
      );
      return savedRecord;
    } catch (error) {
      onError(error);
    }
  };
  const onEdit = async ({ id, content, status }) => {
    const messageType = status ? status : "updated";
    const messages = {
      approved: (0, import_i18n.__)("Note marked as resolved."),
      hold: (0, import_i18n.__)("Note reopened."),
      updated: (0, import_i18n.__)("Note updated.")
    };
    try {
      if (status === "approved" || status === "hold") {
        await saveEntityRecord(
          "root",
          "comment",
          {
            id,
            status
          },
          {
            throwOnError: true
          }
        );
        const newNoteData = {
          post: getCurrentPostId(),
          content: content || "",
          // Empty content for resolve, content for reopen.
          type: "note",
          status,
          parent: id,
          meta: {
            _wp_note_status: status === "approved" ? "resolved" : "reopen"
          }
        };
        await saveEntityRecord("root", "comment", newNoteData, {
          throwOnError: true
        });
      } else {
        const updateData = {
          id,
          content,
          status
        };
        await saveEntityRecord("root", "comment", updateData, {
          throwOnError: true
        });
      }
      createNotice(
        "snackbar",
        messages[messageType] ?? (0, import_i18n.__)("Note updated."),
        {
          type: "snackbar",
          isDismissible: true
        }
      );
    } catch (error) {
      onError(error);
    }
  };
  const onDelete = async (note) => {
    try {
      await deleteEntityRecord("root", "comment", note.id, void 0, {
        throwOnError: true
      });
      if (!note.parent) {
        const clientId = getSelectedBlockClientId();
        const metadata = getBlockAttributes(clientId)?.metadata;
        updateBlockAttributes(clientId, {
          metadata: cleanEmptyObject({
            ...metadata,
            noteId: void 0
          })
        });
      }
      createNotice("snackbar", (0, import_i18n.__)("Note deleted."), {
        type: "snackbar",
        isDismissible: true
      });
    } catch (error) {
      onError(error);
    }
  };
  return { onCreate, onEdit, onDelete };
}
function useEnableFloatingSidebar(enabled = false) {
  const registry = (0, import_data.useRegistry)();
  (0, import_element.useEffect)(() => {
    if (!enabled) {
      return;
    }
    const { getActiveComplementaryArea } = registry.select(import_interface.store);
    const { disableComplementaryArea, enableComplementaryArea } = registry.dispatch(import_interface.store);
    const unsubscribe = registry.subscribe(() => {
      if (getActiveComplementaryArea("core") === null) {
        enableComplementaryArea("core", import_constants.FLOATING_NOTES_SIDEBAR);
      }
    });
    return () => {
      unsubscribe();
      if (getActiveComplementaryArea("core") === import_constants.FLOATING_NOTES_SIDEBAR) {
        disableComplementaryArea("core", import_constants.FLOATING_NOTES_SIDEBAR);
      }
    };
  }, [enabled, registry]);
}
function useFloatingBoard({
  threads,
  selectedNoteId,
  isFloating,
  sidebarRef
}) {
  const [notePositions, setNotePositions] = (0, import_element.useState)({});
  const [store] = (0, import_element.useState)(import_board_store.createBoardStore);
  const heights = (0, import_element.useSyncExternalStore)(store.subscribe, store.getSnapshot);
  (0, import_element.useEffect)(() => {
    if (!isFloating || !sidebarRef?.current) {
      return;
    }
    const panel = sidebarRef.current;
    const blockEl = store.getFirstBlockElement();
    const rootEl = blockEl?.closest(".is-root-container") ?? blockEl;
    const canvas = rootEl ? (0, import_dom.getScrollContainer)(rootEl) : null;
    const applyScroll = () => {
      panel.style.setProperty(
        "--canvas-scroll",
        `${-(canvas?.scrollTop ?? 0)}px`
      );
    };
    const rafId = window.requestAnimationFrame(() => {
      const result = (0, import_utils.calculateNotePositions)({
        threads,
        selectedNoteId,
        blockRects: store.getBlockRects(),
        heights,
        scrollTop: canvas?.scrollTop ?? 0
      });
      setNotePositions(result.positions);
      applyScroll();
    });
    const view = canvas?.ownerDocument?.defaultView;
    const listenerOptions = { passive: true, capture: true };
    view?.addEventListener("scroll", applyScroll, listenerOptions);
    return () => {
      window.cancelAnimationFrame(rafId);
      view?.removeEventListener("scroll", applyScroll, listenerOptions);
    };
  }, [sidebarRef, heights, isFloating, selectedNoteId, store, threads]);
  return {
    notePositions,
    registerThread: store.registerThread,
    unregisterThread: store.unregisterThread
  };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  useEnableFloatingSidebar,
  useFloatingBoard,
  useNoteActions,
  useNoteThreads
});
//# sourceMappingURL=hooks.cjs.map
