import { useEffect } from 'react';
import { $getSelection, $isRangeSelection, EditorState } from 'lexical';
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { trimTextContentFromAnchor } from '@lexical/selection';
import { $restoreEditorState } from '@lexical/utils';

import { lexicalToCrystallizeRichText } from '../../model/lexical-to-crystallize';
import { toText } from '../../model/to-text';

export function MaxLengthPlugin({ maxLength }: { maxLength: number }): null {
  const [editor] = useLexicalComposerContext();

  useEffect(() => {
    let lastRestoredEditorState: EditorState | null = null;

    return editor.registerUpdateListener(({ editorState, prevEditorState }) => {
      editor.update(() => {
        const selection = $getSelection();
        if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
          return;
        }

        const prevTextContent = toText(lexicalToCrystallizeRichText({ editor, editorState: prevEditorState }));
        const textContent = toText(lexicalToCrystallizeRichText({ editor, editorState }));

        if (prevTextContent !== textContent) {
          const textLength = textContent.length;
          const delCount = textLength - maxLength;
          const anchor = selection.anchor;

          if (delCount > 0) {
            // Restore the old editor state instead if the last
            // text content was already at the limit.
            if (prevTextContent.length === maxLength && lastRestoredEditorState !== prevEditorState) {
              lastRestoredEditorState = prevEditorState;
              $restoreEditorState(editor, prevEditorState);
            } else {
              trimTextContentFromAnchor(editor, anchor, delCount);
            }
          }
        }
      });
    });
  }, [editor, maxLength]);

  return null;
}
