import React, { useCallback } from 'react';
import FocusTrap from 'focus-trap-react';
import { atom, useAtom, useSetAtom } from 'jotai';
import {
  Box,
  Dialog,
  Header,
  Icon,
  IconButton,
  Icons,
  Line,
  Overlay,
  OverlayBackdrop,
  OverlayCenter,
  Scroll,
  Text,
  config,
} from 'folds';
import { stopPropagation } from '../../utils/keyboard';
import { editableActiveElement } from '../../utils/dom';
import { useKeyDown } from '../../hooks/useKeyDown';
import { useModalStyle } from '../../hooks/useModalStyle';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { isMacOS } from '../../utils/user-agent';
import { KeySymbol } from '../../utils/key-symbol';
import * as css from './KeyboardShortcutsDialog.css';

/** Global open-state for the keyboard shortcuts help dialog. */
export const keyboardShortcutsDialogAtom = atom<boolean>(false);

/** Read/control the keyboard shortcuts dialog open-state. */
export function useKeyboardShortcutsDialog() {
  const [open, setOpen] = useAtom(keyboardShortcutsDialogAtom);
  const openDialog = useCallback(() => setOpen(true), [setOpen]);
  const closeDialog = useCallback(() => setOpen(false), [setOpen]);
  return { open, openDialog, closeDialog };
}

/**
 * Registers the global `Shift + /` (`?`) shortcut that opens the keyboard
 * shortcuts help dialog. Ignored while the user is typing into an input,
 * textarea or contenteditable so it never steals a literal `?` character.
 *
 * Mount once in the client shell (e.g. `ClientNonUIFeatures`).
 */
export function useKeyboardShortcutsTrigger() {
  const setOpen = useSetAtom(keyboardShortcutsDialogAtom);
  useKeyDown(
    window,
    useCallback(
      (evt: KeyboardEvent) => {
        // Never intercept `?` while the user is typing into a field/editor.
        if (editableActiveElement()) return;
        // `?` is produced by Shift + `/` on the common layouts.
        if (evt.key === '?') {
          evt.preventDefault();
          // Stop RoomView's window-level "type any char → focus composer"
          // handler from also firing — otherwise focus lands in the composer
          // behind the dialog and Escape gets swallowed by the contenteditable.
          evt.stopImmediatePropagation();
          setOpen(true);
        }
      },
      [setOpen],
    ),
  );
}

type ShortcutRow = {
  description: string;
  keys: string[];
};

type ShortcutSection = {
  title: string;
  rows: ShortcutRow[];
};

function ShortcutKeys({ keys }: { keys: string[] }) {
  return (
    <Box as="dd" className={css.ShortcutKeys}>
      {keys.map((key, index) => (
        <kbd key={`${key}-${index}`} className={css.Kbd}>
          {key}
        </kbd>
      ))}
    </Box>
  );
}

/**
 * Accessible keyboard shortcuts help dialog. Renders (as a modal overlay) only
 * while `keyboardShortcutsDialogAtom` is `true`. Open it with the `?` shortcut
 * (see `useKeyboardShortcutsTrigger`) or via `useKeyboardShortcutsDialog`.
 */
export function KeyboardShortcutsDialog() {
  const { open, closeDialog } = useKeyboardShortcutsDialog();
  const modalStyle = useModalStyle(480);
  const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline');

  const modKey = isMacOS() ? KeySymbol.Command : 'Ctrl';

  if (!open) return null;

  const sections: ShortcutSection[] = [
    {
      title: 'General',
      rows: [
        { description: 'Show keyboard shortcuts', keys: ['?'] },
        { description: 'Close open panel, otherwise mark room as read', keys: [KeySymbol.Escape] },
      ],
    },
    {
      title: 'Composer',
      rows: [
        { description: 'Focus the message composer', keys: ['Any character'] },
        {
          description: 'Send message',
          keys: enterForNewline ? [modKey, 'Enter'] : ['Enter'],
        },
        {
          description: 'Insert a new line',
          keys: enterForNewline ? ['Enter'] : [KeySymbol.Shift, 'Enter'],
        },
        { description: 'Send message (always)', keys: [modKey, 'Enter'] },
      ],
    },
    {
      title: 'Messages',
      rows: [
        { description: 'Reveal message actions (react, reply, more)', keys: ['Hover / focus'] },
      ],
    },
  ];

  return (
    <Overlay open backdrop={<OverlayBackdrop />}>
      <OverlayCenter>
        <FocusTrap
          focusTrapOptions={{
            initialFocus: false,
            onDeactivate: closeDialog,
            clickOutsideDeactivates: true,
            escapeDeactivates: stopPropagation,
          }}
        >
          <Dialog
            variant="Surface"
            aria-labelledby="keyboard-shortcuts-dialog-title"
            style={modalStyle}
          >
            <Header
              style={{
                padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
                borderBottomWidth: config.borderWidth.B300,
              }}
              variant="Surface"
              size="500"
            >
              <Box grow="Yes">
                <Text as="h2" size="H4" id="keyboard-shortcuts-dialog-title">
                  Keyboard Shortcuts
                </Text>
              </Box>
              <IconButton size="300" onClick={closeDialog} radii="300" aria-label="Close">
                <Icon src={Icons.Cross} />
              </IconButton>
            </Header>
            <Scroll size="300" hideTrack visibility="Hover">
              <Box style={{ padding: config.space.S400 }} direction="Column" gap="500">
                {sections.map((section, sectionIndex) => (
                  <Box key={section.title} direction="Column" gap="300">
                    {sectionIndex > 0 && <Line variant="Surface" size="300" />}
                    <Text size="L400" priority="400">
                      {section.title}
                    </Text>
                    <Box as="dl" className={css.ShortcutList} direction="Column">
                      {section.rows.map((row) => (
                        <Box
                          key={row.description}
                          className={css.ShortcutRow}
                          direction="Row"
                          alignItems="Center"
                          gap="200"
                        >
                          <Text as="dt" className={css.ShortcutTerm} size="T300">
                            {row.description}
                          </Text>
                          <ShortcutKeys keys={row.keys} />
                        </Box>
                      ))}
                    </Box>
                  </Box>
                ))}
                <Text size="T200" priority="300">
                  {enterForNewline
                    ? 'Enter inserts a new line while “Enter for newline” is enabled in Settings.'
                    : 'Enter sends the message. Enable “Enter for newline” in Settings to swap this.'}
                </Text>
              </Box>
            </Scroll>
          </Dialog>
        </FocusTrap>
      </OverlayCenter>
    </Overlay>
  );
}
