import { Box, config, Icon, Icons, IconSrc, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
import React, { MouseEventHandler, ReactNode, useMemo, useState } from 'react';
import FocusTrap from 'focus-trap-react';
import { stopPropagation } from '../utils/keyboard';
import { ThreadNotificationMode } from '../utils/threadNotifications';
import { useSetThreadNotificationMode } from '../hooks/useThreadNotifications';
import { AsyncStatus } from '../hooks/useAsyncCallback';

export const getThreadNotificationModeIcon = (mode?: ThreadNotificationMode): IconSrc => {
  if (mode === ThreadNotificationMode.Mute) return Icons.BellMute;
  if (mode === ThreadNotificationMode.MentionsOnly) return Icons.BellPing;
  if (mode === ThreadNotificationMode.All) return Icons.BellRing;

  return Icons.Bell;
};

const useThreadNotificationModes = (): ThreadNotificationMode[] =>
  useMemo(
    () => [
      ThreadNotificationMode.Default,
      ThreadNotificationMode.All,
      ThreadNotificationMode.MentionsOnly,
      ThreadNotificationMode.Mute,
    ],
    [],
  );

const useThreadNotificationModeStr = (): Record<ThreadNotificationMode, string> =>
  useMemo(
    () => ({
      [ThreadNotificationMode.Default]: 'Default (participating)',
      [ThreadNotificationMode.All]: 'All replies',
      [ThreadNotificationMode.MentionsOnly]: 'Mentions only',
      [ThreadNotificationMode.Mute]: 'Mute',
    }),
    [],
  );

type ThreadNotificationModeSwitcherProps = {
  roomId: string;
  threadId: string;
  value?: ThreadNotificationMode;
  children: (
    handleOpen: MouseEventHandler<HTMLButtonElement>,
    opened: boolean,
    changing: boolean,
  ) => ReactNode;
};
export function ThreadNotificationModeSwitcher({
  roomId,
  threadId,
  value = ThreadNotificationMode.Default,
  children,
}: ThreadNotificationModeSwitcherProps) {
  const modes = useThreadNotificationModes();
  const modeToStr = useThreadNotificationModeStr();

  const { modeState, setMode } = useSetThreadNotificationMode(roomId, threadId);
  const changing = modeState.status === AsyncStatus.Loading;

  const [menuCords, setMenuCords] = useState<RectCords>();

  const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
    setMenuCords(evt.currentTarget.getBoundingClientRect());
  };

  const handleClose = () => {
    setMenuCords(undefined);
  };

  const handleSelect = (mode: ThreadNotificationMode) => {
    if (changing) return;
    setMode(mode);
    handleClose();
  };

  return (
    <PopOut
      anchor={menuCords}
      offset={5}
      position="Bottom"
      align="End"
      content={
        <FocusTrap
          focusTrapOptions={{
            initialFocus: false,
            onDeactivate: handleClose,
            clickOutsideDeactivates: true,
            isKeyForward: (evt: KeyboardEvent) =>
              evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
            isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
            escapeDeactivates: stopPropagation,
          }}
        >
          <Menu>
            <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
              {modes.map((mode) => (
                <MenuItem
                  key={mode}
                  size="300"
                  variant="Surface"
                  aria-pressed={mode === value}
                  radii="300"
                  disabled={changing}
                  onClick={() => handleSelect(mode)}
                  before={
                    <Icon
                      size="100"
                      src={getThreadNotificationModeIcon(mode)}
                      filled={mode === value}
                    />
                  }
                >
                  <Text size="T300">
                    {mode === value ? <b>{modeToStr[mode]}</b> : modeToStr[mode]}
                  </Text>
                </MenuItem>
              ))}
            </Box>
          </Menu>
        </FocusTrap>
      }
    >
      {children(handleOpenMenu, !!menuCords, changing)}
    </PopOut>
  );
}
