import React, { KeyboardEventHandler, useCallback, useRef, useState } from 'react';
import { isKeyHotkey } from 'is-hotkey';
import { Editor } from 'slate';
import { IconButton, Line, PopOut } from 'folds';
import { Icon, Icons } from '../../components/icons';
import {
  CustomEditor,
  Toolbar,
  EmoticonAutocomplete,
  AutocompletePrefix,
  AutocompleteQuery,
  getAutocompleteQuery,
  createEmoticonElement,
  moveCursor,
  safeFocusEditor,
} from '../../components/editor';
import { EmojiBoard, EmojiBoardTab } from '../../components/emoji-board';
import { UseStateProvider } from '../../components/UseStateProvider';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { useImagePackRooms } from '../../hooks/useImagePackRooms';
import { useAtomValue } from 'jotai';
import { roomToParentsAtom } from '../../state/room/roomToParents';
import { Room } from 'matrix-js-sdk';
import { mobileOrTablet } from '../../utils/user-agent';
import { PluginButtonSlot } from '../settings/plugins/PluginButtonSlot';

type ForumChatComposerProps = {
  editor: Editor;
  roomId: string;
  room: Room;
  placeholder?: string;
  onSend?: () => void;
  showAttachButton?: boolean;
  maxHeight?: string;
};

/** Same chrome as {@link RoomInput} (attach, emoji, toolbar, send). */
export function ForumChatComposer({
  editor,
  roomId,
  room,
  placeholder = 'Send a message…',
  onSend,
  showAttachButton = false,
  maxHeight,
}: ForumChatComposerProps) {
  const [toolbar, setToolbar] = useSetting(settingsAtom, 'editorToolbar');
  const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline');
  const roomToParents = useAtomValue(roomToParentsAtom);
  const imagePackRooms = useImagePackRooms(roomId, roomToParents);
  const emojiBtnRef = useRef<HTMLButtonElement>(null);
  const [autocompleteQuery, setAutocompleteQuery] =
    useState<AutocompleteQuery<AutocompletePrefix>>();
  const handleKeyDown: KeyboardEventHandler = useCallback(
    (evt) => {
      if (
        onSend &&
        (isKeyHotkey('mod+enter', evt) || (!enterForNewline && isKeyHotkey('enter', evt)))
      ) {
        evt.preventDefault();
        onSend();
      }
    },
    [enterForNewline, onSend]
  );

  const handleKeyUp: KeyboardEventHandler = useCallback(
    (evt) => {
      const prevWordRange = getAutocompleteQuery(editor, evt);
      if (prevWordRange?.prefix === AutocompletePrefix.Emoticon) {
        setAutocompleteQuery({ prefix: AutocompletePrefix.Emoticon, range: prevWordRange.range });
        return;
      }
      setAutocompleteQuery(undefined);
    },
    [editor]
  );

  const handleEmoticonSelect = (key: string, shortcode: string) => {
    editor.insertNode(createEmoticonElement(key, shortcode));
    moveCursor(editor);
  };

  const handleCloseAutocomplete = useCallback(() => {
    setAutocompleteQuery(undefined);
    safeFocusEditor(editor);
  }, [editor]);

  return (
    <div>
      {autocompleteQuery?.prefix === AutocompletePrefix.Emoticon && (
        <EmoticonAutocomplete
          imagePackRooms={imagePackRooms}
          editor={editor}
          query={autocompleteQuery}
          requestClose={handleCloseAutocomplete}
        />
      )}
      <CustomEditor
        editor={editor}
        placeholder={placeholder}
        maxHeight={maxHeight}
        onKeyDown={handleKeyDown}
        onKeyUp={handleKeyUp}
        before={showAttachButton ? <PluginButtonSlot location="composer-actions" /> : undefined}
        after={
          <>
            <IconButton
              variant="SurfaceVariant"
              size="300"
              radii="300"
              type="button"
              onClick={() => setToolbar(!toolbar)}
              aria-label="Formatting"
            >
              <Icon src={toolbar ? Icons.AlphabetUnderline : Icons.Alphabet} size="200" />
            </IconButton>
            <UseStateProvider initial={undefined}>
              {(emojiBoardTab: EmojiBoardTab | undefined, setEmojiBoardTab) => (
                <PopOut
                  offset={16}
                  alignOffset={-44}
                  position="Top"
                  align="End"
                  anchor={
                    emojiBoardTab === undefined
                      ? undefined
                      : emojiBtnRef.current?.getBoundingClientRect() ?? undefined
                  }
                  content={
                    <EmojiBoard
                      tab={emojiBoardTab}
                      onTabChange={setEmojiBoardTab}
                      imagePackRooms={imagePackRooms}
                      returnFocusOnDeactivate={false}
                      onEmojiSelect={handleEmoticonSelect}
                      onCustomEmojiSelect={handleEmoticonSelect}
                        requestClose={() => {
                          setEmojiBoardTab((t) => {
                            if (t) {
                              if (!mobileOrTablet()) safeFocusEditor(editor);
                              return undefined;
                            }
                            return t;
                          });
                        }}
                    />
                  }
                >
                  <IconButton
                    ref={emojiBtnRef}
                    aria-pressed={emojiBoardTab === EmojiBoardTab.Emoji}
                    onClick={() => setEmojiBoardTab(EmojiBoardTab.Emoji)}
                    variant="SurfaceVariant"
                    size="300"
                    radii="300"
                    type="button"
                    aria-label="Emoji"
                  >
                    <Icon
                      src={Icons.Smile}
                      size="200"
                      filled={emojiBoardTab === EmojiBoardTab.Emoji}
                    />
                  </IconButton>
                </PopOut>
              )}
            </UseStateProvider>
            <PluginButtonSlot location="text-composer-toolbar" />
            {onSend && (
              <IconButton
                type="button"
                onClick={onSend}
                variant="SurfaceVariant"
                size="300"
                radii="300"
                aria-label="Send"
              >
                <Icon src={Icons.Send} size="200" />
              </IconButton>
            )}
          </>
        }
        bottom={
          toolbar ? (
            <div>
              <Line variant="SurfaceVariant" size="300" />
              <Toolbar />
            </div>
          ) : undefined
        }
      />
    </div>
  );
}
