import React, { forwardRef, useState } from 'react';
import { Room } from 'matrix-js-sdk';
import { useAtomValue } from 'jotai';
import { Box, Line, Menu, MenuItem, Text, config, toRem } from 'folds';
import { Icon, Icons } from '../../components/icons';
import type { HierarchyItem } from '../../hooks/useSpaceHierarchy';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useOpenCreateRoomModal } from '../../state/hooks/createRoomModal';
import { useOpenCreateSpaceModal } from '../../state/hooks/createSpaceModal';
import { AddExistingModal } from '../add-existing';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { usePowerLevels } from '../../hooks/usePowerLevels';
import { useRoomCreators } from '../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../hooks/useRoomPermissions';
import { useOpenSpaceSettings } from '../../state/hooks/spaceSettings';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { useMarkRoomsAsRead } from '../../hooks/useMarkAsRead';
import { useRecursiveChildScopeFactory, useSpaceChildren } from '../../state/hooks/roomList';
import { allRoomsAtom } from '../../state/room-list/roomList';
import { roomToParentsAtom } from '../../state/room/roomToParents';
import { useRoomsUnread } from '../../state/hooks/unread';
import { roomToUnreadAtom } from '../../state/room/roomToUnread';
import { UseStateProvider } from '../../components/UseStateProvider';
import { LeaveSpacePrompt } from '../../components/leave-space-prompt';
import { RemoveInaccessiblePrompt } from '../../components/remove-inaccessible-prompt';
import { InviteUserPrompt } from '../../components/invite-user-prompt';
import { copyToClipboard } from '../../utils/dom';
import { getCanonicalAliasOrRoomId, isRoomAlias } from '../../utils/matrix';
import { getMatrixToRoom } from '../../plugins/matrix-to';
import { getViaServers } from '../../plugins/via-servers';
import { useNavigate } from 'react-router-dom';
import { getSpaceFeedPath, getSpaceLobbyPath } from '../../pages/pathUtils';
import { shouldShowForumLobby } from '../../utils/room';
import { useSpaceFeedSelected } from '../../hooks/router/useSelectedSpace';
import { StateEvent } from '../../../types/matrix/room';

type ForumAddOptions = {
  item: HierarchyItem;
  showAddSpace: boolean;
};

export type OpenAddExistingOptions = {
  parentId: string;
  space: boolean;
};

type SpaceOptionsMenuProps = {
  room: Room;
  requestClose: () => void;
  forumAdd?: ForumAddOptions;
  /** Render Add Existing outside the popout (forum kebab). */
  onOpenAddExisting?: (options: OpenAddExistingOptions) => void;
};

export const SpaceOptionsMenu = forwardRef<HTMLDivElement, SpaceOptionsMenuProps>(
  ({ room, requestClose, forumAdd, onOpenAddExisting }, ref) => {
    const mx = useMatrixClient();
    const navigate = useNavigate();
    const onFeed = useSpaceFeedSelected();
    const isForum = shouldShowForumLobby(room);
    const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
    const [developerTools] = useSetting(settingsAtom, 'developerTools');
    const roomToParents = useAtomValue(roomToParentsAtom);
    const powerLevels = usePowerLevels(room);
    const creators = useRoomCreators(room);

    const permissions = useRoomPermissions(creators, powerLevels);
    const canInvite = permissions.action('invite', mx.getSafeUserId());
    const canEditChildren = permissions.stateEvent(StateEvent.SpaceChild, mx.getSafeUserId());
    const openSpaceSettings = useOpenSpaceSettings();
    const { navigateRoom } = useRoomNavigate();
    const markRoomsAsRead = useMarkRoomsAsRead(mx);

    const [invitePrompt, setInvitePrompt] = useState(false);
    const [addExistingRoom, setAddExistingRoom] = useState(false);
    const [addExistingSpace, setAddExistingSpace] = useState(false);
    const openCreateRoomModal = useOpenCreateRoomModal();
    const openCreateSpaceModal = useOpenCreateSpaceModal();

    const allChild = useSpaceChildren(
      allRoomsAtom,
      room.roomId,
      useRecursiveChildScopeFactory(mx, roomToParents)
    );
    const unread = useRoomsUnread(allChild, roomToUnreadAtom);

    const handleMarkAsRead = () => {
      markRoomsAsRead(allChild, hideActivity);
      requestClose();
    };

    const handleCopyLink = () => {
      const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, room.roomId);
      const viaServers = isRoomAlias(roomIdOrAlias) ? undefined : getViaServers(room);
      copyToClipboard(getMatrixToRoom(roomIdOrAlias, viaServers));
      requestClose();
    };

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

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

    const handleOpenTimeline = () => {
      navigateRoom(room.roomId);
      requestClose();
    };

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

    const handleOpenManage = () => {
      navigate(getSpaceLobbyPath(getCanonicalAliasOrRoomId(mx, room.roomId)));
      requestClose();
    };

    const handleAddTopic = () => {
      if (!forumAdd) return;
      openCreateRoomModal(forumAdd.item.roomId);
      requestClose();
    };

    const handleAddCategory = () => {
      if (!forumAdd) return;
      openCreateSpaceModal(forumAdd.item.roomId);
      requestClose();
    };

    const handleAddExistingTopic = () => {
      if (!forumAdd) return;
      if (onOpenAddExisting) {
        onOpenAddExisting({ parentId: forumAdd.item.roomId, space: false });
        requestClose();
        return;
      }
      setAddExistingRoom(true);
    };

    const handleAddExistingCategory = () => {
      if (!forumAdd) return;
      if (onOpenAddExisting) {
        onOpenAddExisting({ parentId: forumAdd.item.roomId, space: true });
        requestClose();
        return;
      }
      setAddExistingSpace(true);
    };

    return (
      <>
      <Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
        {forumAdd && (
          <>
            <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
              <MenuItem
                onClick={handleAddTopic}
                variant="Primary"
                fill="None"
                size="300"
                after={<Icon size="100" src={Icons.Plus} />}
                radii="300"
              >
                <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                  Add Topic
                </Text>
              </MenuItem>
              <MenuItem
                onClick={handleAddExistingTopic}
                size="300"
                radii="300"
                fill="None"
              >
                <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                  Add Existing Topic
                </Text>
              </MenuItem>
              {forumAdd.showAddSpace && (
                <>
                  <MenuItem
                    onClick={handleAddCategory}
                    size="300"
                    after={<Icon size="100" src={Icons.Plus} />}
                    radii="300"
                    fill="None"
                  >
                    <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                      Add Section
                    </Text>
                  </MenuItem>
                  <MenuItem
                    onClick={handleAddExistingCategory}
                    size="300"
                    radii="300"
                    fill="None"
                  >
                    <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                      Add Existing Section
                    </Text>
                  </MenuItem>
                </>
              )}
            </Box>
            <Line variant="Surface" size="300" />
          </>
        )}
        <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
          {invitePrompt && (
            <InviteUserPrompt
              room={room}
              requestClose={() => {
                setInvitePrompt(false);
                requestClose();
              }}
            />
          )}
          {isForum && !onFeed && (
            <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>
          )}
          {isForum && onFeed && (
            <MenuItem
              onClick={handleOpenManage}
              size="300"
              after={<Icon size="100" src={Icons.Flag} />}
              radii="300"
            >
              <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                Manage
              </Text>
            </MenuItem>
          )}
          <MenuItem
            onClick={handleMarkAsRead}
            size="300"
            after={<Icon size="100" src={Icons.CheckTwice} />}
            radii="300"
            disabled={!unread}
          >
            <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
              Mark as Read
            </Text>
          </MenuItem>
        </Box>
        <Line variant="Surface" size="300" />
        <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
          <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={handleCopyLink}
            size="300"
            after={<Icon size="100" src={Icons.Link} />}
            radii="300"
          >
            <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
              Copy Link
            </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>
          {developerTools && (
            <MenuItem
              onClick={handleOpenTimeline}
              size="300"
              after={<Icon size="100" src={Icons.Terminal} />}
              radii="300"
            >
              <Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
                Event Timeline
              </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={room.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={room.roomId}
                    onDone={requestClose}
                    onCancel={() => setPromptLeave(false)}
                  />
                )}
              </>
            )}
          </UseStateProvider>
        </Box>
      </Menu>
      {forumAdd && addExistingRoom && (
        <AddExistingModal parentId={forumAdd.item.roomId} requestClose={() => setAddExistingRoom(false)} />
      )}
      {forumAdd && addExistingSpace && (
        <AddExistingModal
          space
          parentId={forumAdd.item.roomId}
          requestClose={() => setAddExistingSpace(false)}
        />
      )}
      </>
    );
  }
);
