'use client';

import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React, { createContext, useCallback, useEffect, useMemo, useRef } from 'react';
const baseClass = 'inline-block';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
import { mergeRegister } from '@lexical/utils';
import { getTranslation } from '@payloadcms/translations';
import { Button, Drawer, EditDepthProvider, Form, formatDrawerSlug, FormSubmit, RenderFields, ShimmerEffect, useDocumentInfo, useEditDepth, useServerFunctions, useTranslation } from '@payloadcms/ui';
import { abortAndIgnore } from '@payloadcms/ui/shared';
import { $getNodeByKey, $getSelection, $isNodeSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND } from 'lexical';
import { reduceFieldsToValues } from 'payload/shared';
import { v4 as uuid } from 'uuid';
import { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js';
import { useLexicalDrawer } from '../../../../utilities/fieldsDrawer/useLexicalDrawer.js';
import { $isInlineBlockNode } from '../nodes/InlineBlocksNode.js';
const InlineBlockComponentContext = /*#__PURE__*/createContext({
  initialState: false
});
export const useInlineBlockComponentContext = () => {
  return React.useContext(InlineBlockComponentContext);
};
export const InlineBlockComponent = props => {
  const {
    formData,
    nodeKey
  } = props;
  const [editor] = useLexicalComposerContext();
  const {
    i18n,
    t
  } = useTranslation();
  const {
    fieldProps: {
      featureClientSchemaMap,
      initialLexicalFormState,
      permissions,
      readOnly,
      schemaPath
    },
    uuid: uuidFromContext
  } = useEditorConfigContext();
  const {
    getFormState
  } = useServerFunctions();
  const editDepth = useEditDepth();
  const [initialState, setInitialState] = React.useState(initialLexicalFormState?.[formData.id]?.formState);
  const [CustomLabel, setCustomLabel] = React.useState(
  // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve
  initialState?.['_components']?.customComponents?.BlockLabel);
  const [CustomBlock, setCustomBlock] = React.useState(
  // @ts-expect-error - vestiges of when tsconfig was not strict. Feel free to improve
  initialState?.['_components']?.customComponents?.Block);
  const drawerSlug = formatDrawerSlug({
    slug: `lexical-inlineBlocks-create-${uuidFromContext}-${formData.id}`,
    depth: editDepth
  });
  const {
    toggleDrawer
  } = useLexicalDrawer(drawerSlug, true);
  const inlineBlockElemElemRef = useRef(null);
  const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
  const {
    id,
    collectionSlug,
    getDocPreferences,
    globalSlug
  } = useDocumentInfo();
  const componentMapRenderedBlockPath = `${schemaPath}.lexical_internal_feature.blocks.lexical_inline_blocks.${formData.blockType}`;
  const clientSchemaMap = featureClientSchemaMap['blocks'];
  const blocksField = clientSchemaMap[componentMapRenderedBlockPath][0];
  const clientBlock = blocksField.blocks[0];
  const removeInlineBlock = useCallback(() => {
    editor.update(() => {
      $getNodeByKey(nodeKey)?.remove();
    });
  }, [editor, nodeKey]);
  const $onDelete = useCallback(event => {
    const deleteSelection = $getSelection();
    if (isSelected && $isNodeSelection(deleteSelection)) {
      event.preventDefault();
      editor.update(() => {
        deleteSelection.getNodes().forEach(node => {
          if ($isInlineBlockNode(node)) {
            node.remove();
          }
        });
      });
    }
    return false;
  }, [editor, isSelected]);
  const onClick = useCallback(payload => {
    const event_0 = payload;
    // Check if inlineBlockElemElemRef.target or anything WITHIN inlineBlockElemElemRef.target was clicked
    if (event_0.target === inlineBlockElemElemRef.current || inlineBlockElemElemRef.current?.contains(event_0.target)) {
      if (event_0.shiftKey) {
        setSelected(!isSelected);
      } else {
        if (!isSelected) {
          clearSelection();
          setSelected(true);
        }
      }
      return true;
    }
    return false;
  }, [isSelected, setSelected, clearSelection]);
  useEffect(() => {
    return mergeRegister(editor.registerCommand(CLICK_COMMAND, onClick, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DELETE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW));
  }, [clearSelection, editor, isSelected, nodeKey, $onDelete, setSelected, onClick]);
  const blockDisplayName = clientBlock?.labels?.singular ? getTranslation(clientBlock.labels.singular, i18n) : clientBlock?.slug;
  const onChangeAbortControllerRef = useRef(new AbortController());
  const schemaFieldsPath = `${schemaPath}.lexical_internal_feature.blocks.lexical_inline_blocks.${clientBlock?.slug}.fields`;
  // Initial state for newly created blocks
  useEffect(() => {
    const abortController = new AbortController();
    const awaitInitialState = async () => {
      /*
      * This will only run if a new block is created. For all existing blocks that are loaded when the document is loaded, or when the form is saved,
      * this is not run, as the lexical field RSC will fetch the state server-side and pass it to the client. That way, we avoid unnecessary client-side
      * requests. Though for newly created blocks, we need to fetch the state client-side, as the server doesn't know about the block yet.
      */
      const {
        state
      } = await getFormState({
        id,
        collectionSlug,
        data: formData,
        docPermissions: {
          fields: true
        },
        docPreferences: await getDocPreferences(),
        globalSlug,
        operation: 'update',
        renderAllFields: true,
        schemaPath: schemaFieldsPath,
        signal: abortController.signal
      });
      if (state) {
        setInitialState(state);
        setCustomLabel(state['_components']?.customComponents?.BlockLabel);
        setCustomBlock(state['_components']?.customComponents?.Block);
      }
    };
    if (formData && !initialState) {
      void awaitInitialState();
    }
    return () => {
      abortAndIgnore(abortController);
    };
  }, [getFormState, schemaFieldsPath, id, formData, initialState, collectionSlug, globalSlug, getDocPreferences]);
  /**
  * HANDLE ONCHANGE
  */
  const onChange = useCallback(async ({
    formState: prevFormState,
    submit
  }) => {
    abortAndIgnore(onChangeAbortControllerRef.current);
    const controller = new AbortController();
    onChangeAbortControllerRef.current = controller;
    const {
      state: state_0
    } = await getFormState({
      id,
      collectionSlug,
      docPermissions: {
        fields: true
      },
      docPreferences: await getDocPreferences(),
      formState: prevFormState,
      globalSlug,
      operation: 'update',
      renderAllFields: submit ? true : false,
      schemaPath: schemaFieldsPath,
      signal: controller.signal
    });
    if (!state_0) {
      return prevFormState;
    }
    if (submit) {
      setCustomLabel(state_0['_components']?.customComponents?.BlockLabel);
      setCustomBlock(state_0['_components']?.customComponents?.Block);
    }
    return state_0;
  }, [getFormState, id, collectionSlug, getDocPreferences, globalSlug, schemaFieldsPath]);
  // cleanup effect
  useEffect(() => {
    return () => {
      abortAndIgnore(onChangeAbortControllerRef.current);
    };
  }, []);
  /**
  * HANDLE FORM SUBMIT
  */
  const onFormSubmit = useCallback(formState => {
    const newData = reduceFieldsToValues(formState);
    newData.blockType = formData.blockType;
    editor.update(() => {
      const node_0 = $getNodeByKey(nodeKey);
      if (node_0 && $isInlineBlockNode(node_0)) {
        node_0.setFields(newData);
      }
    });
  }, [editor, nodeKey, formData]);
  const RemoveButton = useMemo(() => () => /*#__PURE__*/_jsx(Button, {
    buttonStyle: "icon-label",
    className: `${baseClass}__removeButton`,
    disabled: readOnly,
    icon: "x",
    onClick: e => {
      e.preventDefault();
      removeInlineBlock();
    },
    round: true,
    size: "small",
    tooltip: t('lexical:blocks:inlineBlocks:remove', {
      label: blockDisplayName
    })
  }), [blockDisplayName, readOnly, removeInlineBlock, t]);
  const EditButton = useMemo(() => () => /*#__PURE__*/_jsx(Button, {
    buttonStyle: "icon-label",
    className: `${baseClass}__editButton`,
    disabled: readOnly,
    el: "button",
    icon: "edit",
    onClick: () => {
      toggleDrawer();
    },
    round: true,
    size: "small",
    tooltip: t('lexical:blocks:inlineBlocks:edit', {
      label: blockDisplayName
    })
  }), [blockDisplayName, readOnly, t, toggleDrawer]);
  const InlineBlockContainer = useMemo(() => ({
    children
  }) => /*#__PURE__*/_jsx("div", {
    className: [baseClass, baseClass + '-' + formData.blockType, isSelected && `${baseClass}--selected`].filter(Boolean).join(' '),
    ref: inlineBlockElemElemRef,
    children: children
  }), [formData.blockType, isSelected]);
  const Label = useMemo(() => {
    if (CustomLabel) {
      return () => CustomLabel;
    } else {
      return () => /*#__PURE__*/_jsx("div", {
        children: getTranslation(clientBlock.labels.singular, i18n)
      });
    }
  }, [CustomLabel, clientBlock.labels, i18n]);
  return /*#__PURE__*/_jsxs(Form, {
    beforeSubmit: [async ({
      formState: formState_0
    }) => {
      // This is only called when form is submitted from drawer
      return await onChange({
        formState: formState_0,
        submit: true
      });
    }],
    disableValidationOnSubmit: true,
    fields: clientBlock.fields,
    initialState: initialState || {},
    onChange: [onChange],
    onSubmit: formState_1 => {
      onFormSubmit(formState_1);
      toggleDrawer();
    },
    uuid: uuid(),
    children: [/*#__PURE__*/_jsx(EditDepthProvider, {
      children: /*#__PURE__*/_jsx(Drawer, {
        className: '',
        slug: drawerSlug,
        title: t(`lexical:blocks:inlineBlocks:${formData?.id ? 'edit' : 'create'}`, {
          label: blockDisplayName ?? t('lexical:blocks:inlineBlocks:label')
        }),
        children: initialState ? /*#__PURE__*/_jsxs(_Fragment, {
          children: [/*#__PURE__*/_jsx(RenderFields, {
            fields: clientBlock.fields,
            forceRender: true,
            parentIndexPath: "",
            parentPath: "" // See Blocks feature path for details as for why this is empty
            ,

            parentSchemaPath: schemaFieldsPath,
            permissions: permissions,
            readOnly: false
          }), /*#__PURE__*/_jsx(FormSubmit, {
            programmaticSubmit: true,
            children: t('fields:saveChanges')
          })]
        }) : null
      })
    }), CustomBlock ? /*#__PURE__*/_jsx(InlineBlockComponentContext.Provider, {
      value: {
        EditButton,
        initialState,
        InlineBlockContainer,
        Label,
        nodeKey,
        RemoveButton
      },
      children: CustomBlock
    }) : /*#__PURE__*/_jsxs(InlineBlockContainer, {
      children: [initialState ? /*#__PURE__*/_jsx(Label, {}) : /*#__PURE__*/_jsx(ShimmerEffect, {
        height: "15px",
        width: "40px"
      }), editor.isEditable() ? /*#__PURE__*/_jsxs("div", {
        className: `${baseClass}__actions`,
        children: [/*#__PURE__*/_jsx(EditButton, {}), /*#__PURE__*/_jsx(RemoveButton, {})]
      }) : null]
    })]
  });
};
//# sourceMappingURL=index.js.map