import { ReactNode, useEffect, useRef, useState } from 'react';
import type { EditorState } from 'lexical';
import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin';
import { ClearEditorPlugin } from '@lexical/react/LexicalClearEditorPlugin';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin';
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin';
import { TablePlugin } from '@lexical/react/LexicalTablePlugin';

import './rich-text-editor.css';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';

import { SharedHistoryContext, useSharedHistoryContext } from './context/SharedHistoryContext';
import { I18nProvider, SupportedLanguages } from './i18n';
import type { I18N } from './i18n/types';
import { composeInitialState } from './model/crystallize-to-lexical';
import { lexicalToCrystallizeRichText } from './model/lexical-to-crystallize';
import { BaseNodes } from './nodes/BaseNodes';
import AutoLinkPlugin from './plugins/AutoLinkPlugin';
import CodeActionMenuPlugin from './plugins/CodeActionMenuPlugin';
import CodeHighlightPlugin from './plugins/CodeHighlightPlugin';
import FloatingLinkEditorPlugin from './plugins/FloatingLinkEditorPlugin';
import FloatingTextFormatToolbarPlugin from './plugins/FloatingTextFormatToolbarPlugin';
import LinkPlugin from './plugins/LinkPlugin';
import ListMaxIndentLevelPlugin from './plugins/ListMaxIndentLevelPlugin';
import { MaxLengthPlugin } from './plugins/MaxLengthPlugin';
import TabFocusPlugin from './plugins/TabFocusPlugin';
import TableCellActionMenuPlugin from './plugins/TableActionMenuPlugin';
import ToolbarPlugin from './plugins/ToolbarPlugin';
import CrystallizeRTEditorTheme from './themes/CrystallizeRTEditorTheme';
import type { CrystallizeRichText } from './types/crystallize-rich-text-types';
import type { CrystallizeRichTextActionMenuItem } from './types/types';

/**
 * Currently disabling this as there is a conflict with someting within
 * the app. @hk have done 15minutes of debugging without finding out what
 * causes the conflict. We can re-visit this at some later time.
 */
// import DraggableBlockPlugin from './plugins/DraggableBlockPlugin';

// Export types
export type { CrystallizeRichText } from './types/crystallize-rich-text-types';
export * from './types/types';

type TRichTextBase = {
  placeholder?: string;
  onChange?: (data: CrystallizeRichText) => void;
  triggerOnChangeOnAutoFocus?: boolean;
  autoFocus?: boolean;
  actionsMenuPrepend?: CrystallizeRichTextActionMenuItem[];
  actionsMenuAppend?: CrystallizeRichTextActionMenuItem[];
  slotPreContent?: ReactNode;
  maxLength?: number;
  editable?: boolean;
  language?: SupportedLanguages;
  labelTranslations?: I18N;
};

export function RichTextEditor({
  initialData,
  editable = true,
  language = 'en',
  labelTranslations,
  ...rest
}: TRichTextBase & {
  initialData?: CrystallizeRichText;
}) {
  return (
    <LexicalComposer
      initialConfig={{
        namespace: 'crystallize-rich-text-editor',
        nodes: [...BaseNodes],
        editable,
        onError: (error: Error) => {
          throw error;
        },
        theme: CrystallizeRTEditorTheme,
        editorState: initialData
          ? composeInitialState({
              richText: initialData,
            })
          : undefined,
      }}
    >
      <I18nProvider language={language} labelTranslations={labelTranslations}>
        <SharedHistoryContext>
          <div className="c-rich-text-editor">
            <RichTextEditorWithoutContext {...rest} editable={editable} />
          </div>
        </SharedHistoryContext>
      </I18nProvider>
    </LexicalComposer>
  );
}

function RichTextEditorWithoutContext({
  placeholder: placeholderText,
  onChange,
  triggerOnChangeOnAutoFocus,
  autoFocus,
  actionsMenuPrepend,
  actionsMenuAppend,
  slotPreContent,
  maxLength,
  editable,
}: TRichTextBase): JSX.Element {
  const { historyState } = useSharedHistoryContext();
  const placeholder = (
    <div className="text-[14px] font-normal text-gray-300-600 italic absolute overflow-hidden text-ellipsis top-0 left-6 right-10 select-none whitespace-nowrap inline-block pointer-events-none ">
      {placeholderText ?? ''}
    </div>
  );

  const [editor] = useLexicalComposerContext();
  const [floatingAnchorElem, setFloatingAnchorElem] = useState<HTMLDivElement | null>(null);
  const [isSmallWidthViewport, setIsSmallWidthViewport] = useState<boolean>(false);
  const firstOnChangeTriggeredRef = useRef(!autoFocus);

  const onRef = (_floatingAnchorElem: HTMLDivElement) => {
    if (_floatingAnchorElem !== null) {
      setFloatingAnchorElem(_floatingAnchorElem);
    }
  };

  // Listen for editable change
  useEffect(() => {
    editor.setEditable(editable || false);
  }, [editable, editor]);

  // Deal with different window sizes
  useEffect(() => {
    const updateViewPortWidth = () => {
      const isNextSmallWidthViewport = window.matchMedia('(max-width: 1025px)').matches;

      if (isNextSmallWidthViewport !== isSmallWidthViewport) {
        setIsSmallWidthViewport(isNextSmallWidthViewport);
      }
    };

    window.addEventListener('resize', updateViewPortWidth);

    return () => {
      window.removeEventListener('resize', updateViewPortWidth);
    };
  }, [isSmallWidthViewport]);

  function onLocalChange(editorState: EditorState) {
    if (onChange) {
      if (triggerOnChangeOnAutoFocus || firstOnChangeTriggeredRef.current) {
        onChange(lexicalToCrystallizeRichText({ editor, editorState }));
      }
    }

    firstOnChangeTriggeredRef.current = true;
  }

  return (
    <>
      <OnChangePlugin onChange={onLocalChange} ignoreSelectionChange />
      <ToolbarPlugin actionsMenuPrepend={actionsMenuPrepend} actionsMenuAppend={actionsMenuAppend} />
      {slotPreContent}
      <div className="editor-container">
        {maxLength != null ? <MaxLengthPlugin maxLength={maxLength} /> : null}
        {!autoFocus ? null : <AutoFocusPlugin />}
        <ClearEditorPlugin />
        <AutoLinkPlugin />

        <HistoryPlugin externalHistoryState={historyState} />

        <RichTextPlugin
          contentEditable={
            <div className="editor-scroller">
              <div className="editor" ref={onRef}>
                <ContentEditable className="ContentEditable__root" />
              </div>
            </div>
          }
          placeholder={placeholder}
          ErrorBoundary={LexicalErrorBoundary}
        />
        <CodeHighlightPlugin />
        <ListPlugin />
        <ListMaxIndentLevelPlugin maxDepth={7} />
        <TablePlugin />
        <LinkPlugin />
        <HorizontalRulePlugin />
        <TabFocusPlugin />
        <TabIndentationPlugin />
        {floatingAnchorElem && !isSmallWidthViewport && (
          <>
            {/* <DraggableBlockPlugin anchorElem={floatingAnchorElem} /> */}
            <CodeActionMenuPlugin anchorElem={floatingAnchorElem} />
            <FloatingLinkEditorPlugin anchorElem={floatingAnchorElem} />
            <TableCellActionMenuPlugin anchorElem={floatingAnchorElem} />
            <FloatingTextFormatToolbarPlugin anchorElem={floatingAnchorElem} />
          </>
        )}
      </div>
    </>
  );
}
