import React, { MouseEventHandler, ReactNode, useCallback, useState } from 'react';
import FocusTrap from 'focus-trap-react';
import { MatrixEvent, Room } from 'matrix-js-sdk';
import {
  Box,
  Line,
  Menu,
  MenuItem,
  PopOut,
  RectCords,
  Text,
} from 'folds';
import { Icon, Icons } from '../../components/icons';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { stopPropagation } from '../../utils/keyboard';
import { EmojiBoard } from '../../components/emoji-board';
import {
  MessageAllReactionItem,
  MessageCopyLinkItem,
  MessageCopyRawTextItem,
  MessageDeleteItem,
  MessagePinItem,
  MessageQuickReactions,
  MessageReadReceiptItem,
  MessageReportItem,
  MessageSourceCodeItem,
} from '../room/message/Message';
import * as menuCss from '../room/message/styles.css';
import { ForumMessageMenuProvider } from './ForumMessageMenuContext';
import { useForumMessageReactions } from './useForumMessageReactions';

type ForumMessageContextMenuProps = {
  room: Room;
  mEvent: MatrixEvent | undefined;
  imagePackRooms: Room[];
  disabled?: boolean;
  canEdit?: boolean;
  canDelete?: boolean;
  onReply: () => void;
  onEdit?: () => void;
  onDeleted?: () => void;
  className?: string;
  children: ReactNode;
};

export function ForumMessageContextMenu({
  room,
  mEvent,
  imagePackRooms,
  disabled,
  canEdit,
  canDelete,
  onReply,
  onEdit,
  onDeleted,
  className,
  children,
}: ForumMessageContextMenuProps) {
  const mx = useMatrixClient();
  const [menuAnchor, setMenuAnchor] = useState<RectCords>();
  const [emojiBoardAnchor, setEmojiBoardAnchor] = useState<RectCords>();
  const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
  const [developerTools] = useSetting(settingsAtom, 'developerTools');

  const {
    canSendReaction,
    canPinEvent,
    reactionRelations,
    hasReactions,
    handleReactionToggle,
    eventId,
  } = useForumMessageReactions(room, mEvent);

  const openMenu = useCallback((anchor: RectCords) => {
    setMenuAnchor(anchor);
  }, []);

  const closeMenu = useCallback(() => {
    setMenuAnchor(undefined);
  }, []);

  const handleContextMenu: MouseEventHandler<HTMLDivElement> = useCallback(
    (evt) => {
      if (disabled || !mEvent || evt.altKey || !window.getSelection()?.isCollapsed) return;
      const tag = (evt.target as HTMLElement).tagName;
      if (tag.toLowerCase() === 'a' || tag.toLowerCase() === 'img') return;
      evt.preventDefault();
      setMenuAnchor({
        x: evt.clientX,
        y: evt.clientY,
        width: 0,
        height: 0,
      });
    },
    [disabled, mEvent]
  );

  const handleAddReactions: MouseEventHandler<HTMLButtonElement> = useCallback(() => {
    const rect = menuAnchor;
    closeMenu();
    setTimeout(() => {
      setEmojiBoardAnchor(rect);
    }, 100);
  }, [closeMenu, menuAnchor]);

  if (!mEvent) {
    return <div className={className}>{children}</div>;
  }

  return (
    <ForumMessageMenuProvider openMenu={openMenu}>
      <div className={className} onContextMenu={handleContextMenu}>
        {children}
        <PopOut
          anchor={menuAnchor}
          position="Bottom"
          align={menuAnchor?.width === 0 ? 'Start' : 'End'}
          offset={menuAnchor?.width === 0 ? 0 : undefined}
          content={
            <FocusTrap
              focusTrapOptions={{
                initialFocus: false,
                onDeactivate: closeMenu,
                clickOutsideDeactivates: true,
                isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
                isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
                escapeDeactivates: stopPropagation,
              }}
            >
              <Menu>
                {canSendReaction && (
                  <MessageQuickReactions
                    onReaction={(key, shortcode) => {
                      if (eventId) handleReactionToggle(eventId, key, shortcode);
                      closeMenu();
                    }}
                  />
                )}
                <Box direction="Column" gap="100" className={menuCss.MessageMenuGroup}>
                  {canSendReaction && (
                    <MenuItem
                      size="300"
                      after={<Icon size="100" src={Icons.SmilePlus} />}
                      radii="300"
                      onClick={handleAddReactions}
                    >
                      <Text className={menuCss.MessageMenuItemText} as="span" size="T300" truncate>
                        Add Reaction
                      </Text>
                    </MenuItem>
                  )}
                  {hasReactions && reactionRelations && (
                    <MessageAllReactionItem
                      room={room}
                      relations={reactionRelations}
                      onClose={closeMenu}
                    />
                  )}
                  <MenuItem
                    size="300"
                    after={<Icon size="100" src={Icons.ReplyArrow} />}
                    radii="300"
                    onClick={() => {
                      onReply();
                      closeMenu();
                    }}
                  >
                    <Text className={menuCss.MessageMenuItemText} as="span" size="T300" truncate>
                      Reply
                    </Text>
                  </MenuItem>
                  {canEdit && onEdit && (
                    <MenuItem
                      size="300"
                      after={<Icon size="100" src={Icons.Pencil} />}
                      radii="300"
                      onClick={() => {
                        onEdit();
                        closeMenu();
                      }}
                    >
                      <Text className={menuCss.MessageMenuItemText} as="span" size="T300" truncate>
                        Edit Message
                      </Text>
                    </MenuItem>
                  )}
                  {!hideActivity && eventId && (
                    <MessageReadReceiptItem room={room} eventId={eventId} onClose={closeMenu} />
                  )}
                  {developerTools && (
                    <MessageSourceCodeItem room={room} mEvent={mEvent} onClose={closeMenu} />
                  )}
                  <MessageCopyLinkItem room={room} mEvent={mEvent} onClose={closeMenu} />
                  <MessageCopyRawTextItem mEvent={mEvent} onClose={closeMenu} />
                  {canPinEvent && (
                    <MessagePinItem room={room} mEvent={mEvent} onClose={closeMenu} />
                  )}
                </Box>
                {((!mEvent.isRedacted() && canDelete) || mEvent.getSender() !== mx.getUserId()) && (
                  <>
                    <Line size="300" />
                    <Box direction="Column" gap="100" className={menuCss.MessageMenuGroup}>
                      {!mEvent.isRedacted() && canDelete && (
                        <MessageDeleteItem
                          room={room}
                          mEvent={mEvent}
                          onClose={() => {
                            closeMenu();
                            onDeleted?.();
                          }}
                        />
                      )}
                      {mEvent.getSender() !== mx.getUserId() && (
                        <MessageReportItem room={room} mEvent={mEvent} onClose={closeMenu} />
                      )}
                    </Box>
                  </>
                )}
              </Menu>
            </FocusTrap>
          }
        />
        {canSendReaction && (
          <PopOut
            position="Bottom"
            align={emojiBoardAnchor?.width === 0 ? 'Start' : 'End'}
            offset={emojiBoardAnchor?.width === 0 ? 0 : undefined}
            anchor={emojiBoardAnchor}
            content={
              <EmojiBoard
                imagePackRooms={imagePackRooms}
                returnFocusOnDeactivate={false}
                allowTextCustomEmoji
                onEmojiSelect={(key) => {
                  if (eventId) handleReactionToggle(eventId, key);
                  setEmojiBoardAnchor(undefined);
                }}
                onCustomEmojiSelect={(mxc, shortcode) => {
                  if (eventId) handleReactionToggle(eventId, mxc, shortcode);
                  setEmojiBoardAnchor(undefined);
                }}
                requestClose={() => setEmojiBoardAnchor(undefined)}
              />
            }
          >
            <span hidden aria-hidden />
          </PopOut>
        )}
      </div>
    </ForumMessageMenuProvider>
  );
}

export { useForumMessageReactions };
