import React, { useCallback, useMemo, useRef } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Box, Button, Text, config } from 'folds';
import { EventType } from 'matrix-js-sdk';
import { ReactEditor } from 'slate-react';
import { Transforms } from 'slate';
import { isKeyHotkey } from 'is-hotkey';
import { useStateEvent } from '../../hooks/useStateEvent';
import { StateEvent } from '../../../types/matrix/room';
import { usePowerLevelsContext } from '../../hooks/usePowerLevels';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useEditor } from '../../components/editor';
import { RoomInputPlaceholder } from './RoomInputPlaceholder';
import { RoomTimeline } from './RoomTimeline';
import { RoomViewTyping } from './RoomViewTyping';
import { RoomTombstone } from './RoomTombstone';
import { RoomInput } from './RoomInput';
import { RoomViewFollowing, RoomViewFollowingPlaceholder } from './RoomViewFollowing';
import { Page } from '../../components/page';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { useTheme, ThemeKind } from '../../hooks/useTheme';
import { useReducedMotion } from '../../hooks/useReducedMotion';
import { getChatBg } from '../lotus/chatBackground';
import { useKeyDown } from '../../hooks/useKeyDown';
import { editableActiveElement } from '../../utils/dom';
import { useRoomPermissions } from '../../hooks/useRoomPermissions';
import { useRoomCreators } from '../../hooks/useRoomCreators';
import { useRoom } from '../../hooks/useRoom';

const FN_KEYS_REGEX = /^F\d+$/;
const shouldFocusMessageField = (evt: KeyboardEvent): boolean => {
  const { code } = evt;
  if (evt.metaKey || evt.altKey || evt.ctrlKey) {
    return false;
  }

  if (FN_KEYS_REGEX.test(code)) return false;

  if (
    code.startsWith('OS') ||
    code.startsWith('Meta') ||
    code.startsWith('Shift') ||
    code.startsWith('Alt') ||
    code.startsWith('Control') ||
    code.startsWith('Arrow') ||
    code.startsWith('Page') ||
    code.startsWith('End') ||
    code.startsWith('Home') ||
    code === 'Tab' ||
    code === 'Space' ||
    code === 'Enter' ||
    code === 'NumLock' ||
    code === 'ScrollLock'
  ) {
    return false;
  }

  return true;
};

export function RoomView({ eventId }: { eventId?: string }) {
  const roomInputRef = useRef<HTMLDivElement>(null) as React.RefObject<HTMLDivElement>;
  const roomViewRef = useRef<HTMLDivElement>(null) as React.RefObject<HTMLDivElement>;
  const [chatBackground] = useSetting(settingsAtom, 'chatBackground');
  const [lotusTerminal] = useSetting(settingsAtom, 'lotusTerminal');
  const [pauseAnimations] = useSetting(settingsAtom, 'pauseAnimations');
  const theme = useTheme();
  const isDark = theme.kind === ThemeKind.Dark;
  const reduced = useReducedMotion();

  const [hideActivity] = useSetting(settingsAtom, 'hideActivity');

  const room = useRoom();
  const { roomId } = room;
  const editor = useEditor();

  const mx = useMatrixClient();

  const tombstoneEvent = useStateEvent(room, StateEvent.RoomTombstone);
  const powerLevels = usePowerLevelsContext();
  const creators = useRoomCreators(room);

  const permissions = useRoomPermissions(creators, powerLevels);
  const canMessage = permissions.event(EventType.RoomMessage, mx.getSafeUserId());

  useKeyDown(
    window,
    useCallback(
      (evt) => {
        if (editableActiveElement()) return;
        const portalContainer = document.getElementById('portalContainer');
        if (portalContainer && portalContainer.children.length > 0) {
          return;
        }
        if (shouldFocusMessageField(evt) || isKeyHotkey('mod+v', evt)) {
          ReactEditor.focus(editor);
        }
      },
      [editor],
    ),
  );

  // Apply the background directly to Page so it overrides PageRoot's opaque
  // Background.Container color. SidebarNav mirrors it onto document.body separately
  // so the glassmorphism sidebar can blur through it.
  const chatBgStyle = useMemo(() => {
    if (chatBackground !== 'none')
      return getChatBg(chatBackground, isDark, pauseAnimations || reduced);
    if (lotusTerminal) return getChatBg('tactical', isDark, pauseAnimations || reduced);
    return {};
  }, [chatBackground, lotusTerminal, isDark, pauseAnimations, reduced]);

  return (
    <Page ref={roomViewRef} style={chatBgStyle}>
      <Box grow="Yes" direction="Column">
        <ErrorBoundary
          fallback={
            <Box
              grow="Yes"
              direction="Column"
              alignItems="Center"
              justifyContent="Center"
              gap="400"
              style={{ padding: config.space.S400, opacity: 0.7 }}
            >
              <Text size="H4">Timeline unavailable</Text>
              <Text size="T300" align="Center">
                An error occurred while rendering messages. Try refreshing the page.
              </Text>
            </Box>
          }
        >
          <RoomTimeline
            key={roomId}
            room={room}
            eventId={eventId}
            roomInputRef={roomInputRef}
            editor={editor}
          />
        </ErrorBoundary>
        <RoomViewTyping room={room} />
      </Box>
      <Box shrink="No" direction="Column">
        <div style={{ padding: `0 ${config.space.S400}` }}>
          {tombstoneEvent ? (
            <RoomTombstone
              roomId={roomId}
              body={tombstoneEvent.getContent().body}
              replacementRoomId={tombstoneEvent.getContent().replacement_room}
            />
          ) : (
            <>
              {canMessage && (
                <ErrorBoundary
                  onReset={() => {
                    // The composer crash is a transient bad-selection render
                    // (e.g. after an autocomplete insert); the draft content is
                    // intact. Clear the selection so the remounted composer can
                    // render — the user clicks in to continue, no page refresh.
                    try {
                      Transforms.deselect(editor);
                    } catch {
                      /* editor already in a safe state */
                    }
                  }}
                  fallbackRender={({ resetErrorBoundary }) => (
                    <RoomInputPlaceholder
                      role="alert"
                      style={{ padding: config.space.S200 }}
                      direction="Column"
                      alignItems="Center"
                      justifyContent="Center"
                      gap="200"
                    >
                      <Text align="Center">The message composer hit a snag.</Text>
                      <Button
                        size="300"
                        variant="Secondary"
                        fill="Soft"
                        radii="300"
                        onClick={resetErrorBoundary}
                      >
                        <Text size="B300">Reload composer</Text>
                      </Button>
                    </RoomInputPlaceholder>
                  )}
                >
                  <RoomInput
                    room={room}
                    editor={editor}
                    roomId={roomId}
                    fileDropContainerRef={roomViewRef}
                    ref={roomInputRef}
                  />
                </ErrorBoundary>
              )}
              {!canMessage && (
                <RoomInputPlaceholder
                  style={{ padding: config.space.S200 }}
                  alignItems="Center"
                  justifyContent="Center"
                >
                  <Text align="Center">You do not have permission to post in this room</Text>
                </RoomInputPlaceholder>
              )}
            </>
          )}
        </div>
        {hideActivity ? <RoomViewFollowingPlaceholder /> : <RoomViewFollowing room={room} />}
      </Box>
    </Page>
  );
}
