import React, { MouseEventHandler, forwardRef, useEffect, useMemo, useRef, useState } from 'react';
import { Avatar, Box, IconButton, Line, Menu, MenuItem, PopOut, RectCords, Text, Tooltip, TooltipProvider, config, toRem } from 'folds';
import { Icon, Icons } from '../../components/icons';
import FocusTrap from 'focus-trap-react';
import { PageHeader } from '../../components/page';
import { useSetSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { useRoomAvatar, useRoomName } from '../../hooks/useRoomMeta';
import { useSpace } from '../../hooks/useSpace';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { RoomAvatar } from '../../components/room-avatar';
import { nameInitials } from '../../utils/common';
import * as css from './LobbyHeader.css';
import { IPowerLevels } from '../../hooks/usePowerLevels';
import { UseStateProvider } from '../../components/UseStateProvider';
import { LeaveSpacePrompt } from '../../components/leave-space-prompt';
import { RemoveInaccessiblePrompt } from '../../components/remove-inaccessible-prompt';
import { stopPropagation } from '../../utils/keyboard';
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
import { useBackRoute } from '../../hooks/useBackRoute';
import { mxcUrlToHttp } from '../../utils/matrix';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { useOpenSpaceSettings } from '../../state/hooks/spaceSettings';
import { useRoomCreators } from '../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../hooks/useRoomPermissions';
import { InviteUserPrompt } from '../../components/invite-user-prompt';
import { AddExistingModal } from '../add-existing';
import { SpeechBubble } from '../../components/speech-bubble/SpeechBubble';
import { SpaceOptionsMenu, type OpenAddExistingOptions } from '../space/SpaceOptionsMenu';
import type { HierarchyItemSpace } from '../../hooks/useSpaceHierarchy';
import { useNavigate } from 'react-router-dom';
import { getCanonicalAliasOrRoomId } from '../../utils/matrix';
import { getSpaceFeedPath } from '../../pages/pathUtils';
import { shouldShowForumLobby } from '../../utils/room';
import { useForumBoardContextOptionally } from '../forum/ForumBoardContext';
import { StateEvent } from '../../../types/matrix/room';

type LobbyMenuProps = {
  powerLevels: IPowerLevels;
  requestClose: () => void;
};
const LobbyMenu = forwardRef<HTMLDivElement, LobbyMenuProps>(
  ({ powerLevels, requestClose }, ref) => {
    const mx = useMatrixClient();
    const navigate = useNavigate();
    const space = useSpace();
    const isForum = shouldShowForumLobby(space);
    const creators = useRoomCreators(space);

    const permissions = useRoomPermissions(creators, powerLevels);
    const canInvite = permissions.action('invite', mx.getSafeUserId());
    const canEditChildren = permissions.stateEvent(StateEvent.SpaceChild, mx.getSafeUserId());
    const openSpaceSettings = useOpenSpaceSettings();

    const [invitePrompt, setInvitePrompt] = useState(false);

    const handleInvite = () => {
      setInvitePrompt(true);
    };

    const handleRoomSettings = () => {
      openSpaceSettings(space.roomId);
      requestClose();
    };

    const handleOpenFeed = () => {
      navigate(getSpaceFeedPath(getCanonicalAliasOrRoomId(mx, space.roomId)));
      requestClose();
    };

    return (
      <Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
        {invitePrompt && (
          <InviteUserPrompt
            room={space}
            requestClose={() => {
              setInvitePrompt(false);
              requestClose();
            }}
          />
        )}
        <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
          {isForum && (
            <MenuItem
              onClick={handleOpenFeed}
              size="300"
              after={<Icon size="100" src={Icons.Thread} />}
              radii="300"
            >
              <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                Feed
              </Text>
            </MenuItem>
          )}
          <MenuItem
            onClick={handleInvite}
            variant="Primary"
            fill="None"
            size="300"
            after={<Icon size="100" src={Icons.UserPlus} />}
            radii="300"
            aria-pressed={invitePrompt}
            disabled={!canInvite}
          >
            <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
              Invite
            </Text>
          </MenuItem>
          <MenuItem
            onClick={handleRoomSettings}
            size="300"
            after={<Icon size="100" src={Icons.Setting} />}
            radii="300"
          >
            <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
              Space Settings
            </Text>
          </MenuItem>
        </Box>
        <Line variant="Surface" size="300" />
        <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
          {canEditChildren && (
            <UseStateProvider initial={false}>
              {(promptRemove, setPromptRemove) => (
                <>
                  <MenuItem
                    onClick={() => setPromptRemove(true)}
                    variant="Critical"
                    fill="None"
                    size="300"
                    after={<Icon size="100" src={Icons.Delete} />}
                    radii="300"
                    aria-pressed={promptRemove}
                  >
                    <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                      Remove Inaccessible
                    </Text>
                  </MenuItem>
                  {promptRemove && (
                    <RemoveInaccessiblePrompt
                      roomId={space.roomId}
                      onDone={requestClose}
                      onCancel={() => setPromptRemove(false)}
                    />
                  )}
                </>
              )}
            </UseStateProvider>
          )}
          <UseStateProvider initial={false}>
            {(promptLeave, setPromptLeave) => (
              <>
                <MenuItem
                  onClick={() => setPromptLeave(true)}
                  variant="Critical"
                  fill="None"
                  size="300"
                  after={<Icon size="100" src={Icons.ArrowGoLeft} />}
                  radii="300"
                  aria-pressed={promptLeave}
                >
                  <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                    Leave Space
                  </Text>
                </MenuItem>
                {promptLeave && (
                  <LeaveSpacePrompt
                    roomId={space.roomId}
                    onDone={requestClose}
                    onCancel={() => setPromptLeave(false)}
                  />
                )}
              </>
            )}
          </UseStateProvider>
        </Box>
      </Menu>
    );
  }
);

type LobbyHeaderProps = {
  showProfile?: boolean;
  /** Space name on the left + add room/space + ⋮ menu (forum toolbar). */
  showSpaceToolbar?: boolean;
  powerLevels: IPowerLevels;
};
export function LobbyHeader({ showProfile, showSpaceToolbar, powerLevels }: LobbyHeaderProps) {
  const mx = useMatrixClient();
  const useAuthentication = useMediaAuthentication();
  const space = useSpace();
  const creators = useRoomCreators(space);
  const spacePermissions = useRoomPermissions(creators, powerLevels);
  const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
  const [menuAnchor, setMenuAnchor] = useState<RectCords>();
  const [addExisting, setAddExisting] = useState<OpenAddExistingOptions | null>(null);
  const screenSize = useScreenSizeContext();
  const { showInPageHeader, goBack } = useBackRoute();

  const name = useRoomName(space);
  const avatarMxc = useRoomAvatar(space);
  const avatarUrl = avatarMxc
    ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined
    : undefined;

  const forumBoard = useForumBoardContextOptionally();
  const menuWrapperRef = useRef<HTMLDivElement | null>(null);
  const menuTriggerElRef = useRef<HTMLButtonElement | null>(null);
  const addParent = useMemo(() => {
    const rootId = space.roomId;
    if (!forumBoard) {
      return { roomId: rootId, showAddSpace: true };
    }
    if (forumBoard.query.category) {
      const section = forumBoard.sections.find((s) => s.title === forumBoard.query.category);
      if (section?.spaceId) {
        return { roomId: section.spaceId, showAddSpace: false };
      }
    }
    return { roomId: rootId, showAddSpace: true };
  }, [forumBoard, space.roomId]);

  const addParentItem: HierarchyItemSpace = useMemo(
    () => ({
      roomId: addParent.roomId,
      content: { via: [] },
      ts: 0,
      space: true,
      parentId: addParent.roomId === space.roomId ? undefined : space.roomId,
    }),
    [addParent.roomId, space.roomId]
  );

  const canEditChildren = Boolean(
    spacePermissions.stateEvent(StateEvent.SpaceChild, mx.getSafeUserId())
  );

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

  useEffect(() => {
    if (!showSpaceToolbar || !menuAnchor || addExisting) return;

    let outsideTimer: number | undefined;
    const clearOutsideTimer = () => {
      if (outsideTimer) {
        window.clearTimeout(outsideTimer);
        outsideTimer = undefined;
      }
    };

    const closeMenu = () => {
      clearOutsideTimer();
      setMenuAnchor(undefined);
    };

    const isInside = (node: Node | null) => {
      if (!node) return false;
      return Boolean(
        menuWrapperRef.current?.contains(node) || menuTriggerElRef.current?.contains(node)
      );
    };

    const handlePointerDown = (evt: MouseEvent | TouchEvent) => {
      const node = evt.target as Node | null;
      if (!isInside(node)) {
        closeMenu();
      }
    };

    const handlePointerMove = (evt: PointerEvent | MouseEvent) => {
      const node = evt.target as Node | null;
      const inside = isInside(node);
      if (inside) {
        clearOutsideTimer();
        return;
      }
      if (!outsideTimer) {
        outsideTimer = window.setTimeout(closeMenu, 3000);
      }
    };

    document.addEventListener('mousedown', handlePointerDown, true);
    document.addEventListener('touchstart', handlePointerDown, true);
    document.addEventListener('pointermove', handlePointerMove, true);
    document.addEventListener('mousemove', handlePointerMove, true);

    return () => {
      clearOutsideTimer();
      document.removeEventListener('mousedown', handlePointerDown, true);
      document.removeEventListener('touchstart', handlePointerDown, true);
      document.removeEventListener('pointermove', handlePointerMove, true);
      document.removeEventListener('mousemove', handlePointerMove, true);
    };
  }, [addExisting, menuAnchor, showSpaceToolbar]);

  if (showSpaceToolbar) {
    return (
      <>
      <PageHeader outlined>
        <Box grow="Yes" alignItems="Center" gap="300">
          {showInPageHeader && (
            <Box shrink="No">
              <IconButton onClick={goBack} aria-label="Back">
                <Icon src={Icons.ArrowLeft} />
              </IconButton>
            </Box>
          )}
          <Avatar size="300" shrink="No">
            <RoomAvatar
              roomId={space.roomId}
              src={avatarUrl}
              alt={name}
              renderFallback={() => <Text size="H4">{nameInitials(name)}</Text>}
            />
          </Avatar>
          <Text size="H3" truncate style={{ minWidth: 0 }}>
            {name}
          </Text>
          <Box grow="Yes" />
          <TooltipProvider
            position="Bottom"
            align="End"
            offset={4}
            tooltip={
              <Tooltip>
                <Text>More Options</Text>
              </Tooltip>
            }
          >
            {(triggerRef) => (
              <IconButton
                onClick={handleOpenMenu}
                ref={triggerRef}
                aria-pressed={!!menuAnchor}
                variant="SurfaceVariant"
                fill="None"
                size="300"
                radii="300"
              >
                <Icon size="400" src={Icons.VerticalDots} />
              </IconButton>
            )}
          </TooltipProvider>
          <PopOut
            anchor={menuAnchor}
            position="Bottom"
            align="End"
            content={
              <FocusTrap
                focusTrapOptions={{
                  initialFocus: false,
                  returnFocusOnDeactivate: false,
                  onDeactivate: () => setMenuAnchor(undefined),
                  clickOutsideDeactivates: true,
                  isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
                  isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
                  escapeDeactivates: stopPropagation,
                }}
              >
                <div ref={menuWrapperRef}>
                  <SpeechBubble variant="menu" tail="top" tailX="calc(100% - 22px)">
                    <SpaceOptionsMenu
                      room={space}
                      requestClose={() => setMenuAnchor(undefined)}
                      onOpenAddExisting={(options) => {
                        setAddExisting(options);
                        setMenuAnchor(undefined);
                      }}
                      forumAdd={
                        forumBoard && canEditChildren
                          ? {
                              item: addParentItem,
                              showAddSpace: addParent.showAddSpace,
                            }
                          : undefined
                      }
                    />
                  </SpeechBubble>
                </div>
              </FocusTrap>
            }
          />
        </Box>
      </PageHeader>
      {addExisting && (
        <AddExistingModal
          parentId={addExisting.parentId}
          space={addExisting.space}
          requestClose={() => setAddExisting(null)}
        />
      )}
      </>
    );
  }

  return (
    <PageHeader className={showProfile ? undefined : css.Header} balance>
      <Box grow="Yes" alignItems="Center" gap="200">
        {showInPageHeader ? (
          <>
            <Box shrink="No">
              <IconButton onClick={goBack} aria-label="Back">
                <Icon src={Icons.ArrowLeft} />
              </IconButton>
            </Box>
            <Box grow="Yes" justifyContent="Center">
              {showProfile && (
                <Text size="H3" truncate>
                  {name}
                </Text>
              )}
            </Box>
          </>
        ) : (
          <>
            <Box grow="Yes" basis="No" />
            <Box justifyContent="Center" alignItems="Center" gap="300">
              {showProfile && (
                <>
                  <Avatar size="300">
                    <RoomAvatar
                      roomId={space.roomId}
                      src={avatarUrl}
                      alt={name}
                      renderFallback={() => <Text size="H4">{nameInitials(name)}</Text>}
                    />
                  </Avatar>
                  <Text size="H3" truncate>
                    {name}
                  </Text>
                </>
              )}
            </Box>
          </>
        )}
        <Box
          shrink="No"
          grow={screenSize === ScreenSize.Mobile ? 'No' : 'Yes'}
          basis={screenSize === ScreenSize.Mobile ? 'Yes' : 'No'}
          justifyContent="End"
        >
          {screenSize !== ScreenSize.Mobile && (
            <TooltipProvider
              position="Bottom"
              offset={4}
              tooltip={
                <Tooltip>
                  <Text>Members</Text>
                </Tooltip>
              }
            >
              {(triggerRef) => (
                <IconButton ref={triggerRef} onClick={() => setPeopleDrawer((drawer) => !drawer)}>
                  <Icon size="400" src={Icons.User} />
                </IconButton>
              )}
            </TooltipProvider>
          )}
          <TooltipProvider
            position="Bottom"
            align="End"
            offset={4}
            tooltip={
              <Tooltip>
                <Text>More Options</Text>
              </Tooltip>
            }
          >
            {(triggerRef) => (
              <IconButton onClick={handleOpenMenu} ref={triggerRef} aria-pressed={!!menuAnchor}>
                <Icon size="400" src={Icons.VerticalDots} filled={!!menuAnchor} />
              </IconButton>
            )}
          </TooltipProvider>
          <PopOut
            anchor={menuAnchor}
            position="Bottom"
            align="End"
            content={
              <FocusTrap
                focusTrapOptions={{
                  initialFocus: false,
                  returnFocusOnDeactivate: false,
                  onDeactivate: () => setMenuAnchor(undefined),
                  clickOutsideDeactivates: true,
                  isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
                  isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
                  escapeDeactivates: stopPropagation,
                }}
              >
                <LobbyMenu
                  powerLevels={powerLevels}
                  requestClose={() => setMenuAnchor(undefined)}
                />
              </FocusTrap>
            }
          />
        </Box>
      </Box>
    </PageHeader>
  );
}
