import { Box, config, Icon, Icons, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
import { CallMembership } from 'matrix-js-sdk/lib/matrixrtc/CallMembership';
import React, { useState } from 'react';
import FocusTrap from 'focus-trap-react';
import { Room } from 'matrix-js-sdk';
import { UserAvatar } from '../../components/user-avatar';
import { getMemberAvatarMxc, getMemberDisplayName } from '../../utils/room';
import { getMxIdLocalPart, mxcUrlToHttp } from '../../utils/matrix';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { StackedAvatar } from '../../components/stacked-avatar';
import { useOpenUserRoomProfile } from '../../state/hooks/userRoomProfile';
import { stopPropagation } from '../../utils/keyboard';
import { CallEmbed } from '../../plugins/call/CallEmbed';
import * as css from './styles.css';

type ParticipantMenuProps = {
  anchor: RectCords;
  name: string;
  userId: string;
  room: Room;
  callEmbed?: CallEmbed;
  onClose: () => void;
  profileCords: DOMRect;
};
function ParticipantMenu({
  anchor,
  name,
  userId,
  room,
  callEmbed,
  onClose,
  profileCords,
}: ParticipantMenuProps) {
  const openUserProfile = useOpenUserRoomProfile();

  const handleViewProfile = () => {
    onClose();
    openUserProfile(room.roomId, undefined, userId, profileCords, 'Top');
  };

  const handleFocusCamera = () => {
    onClose();
    callEmbed?.control.focusCameraParticipant(userId);
  };

  return (
    <PopOut
      anchor={anchor}
      align="Start"
      position="Top"
      content={
        <FocusTrap
          focusTrapOptions={{
            initialFocus: false,
            onDeactivate: onClose,
            clickOutsideDeactivates: true,
            escapeDeactivates: stopPropagation,
          }}
        >
          <Menu variant="Surface" style={{ minWidth: 160, padding: config.space.S100 }}>
            <Box direction="Column">
              <Text
                size="L400"
                style={{
                  padding: `${config.space.S100} ${config.space.S200}`,
                  opacity: 0.6,
                }}
                truncate
              >
                {name}
              </Text>
              {callEmbed && (
                <MenuItem
                  size="300"
                  variant="Surface"
                  radii="300"
                  before={<Icon size="100" src={Icons.VideoCamera} />}
                  onClick={handleFocusCamera}
                >
                  <Text size="B300">Focus camera</Text>
                </MenuItem>
              )}
              <MenuItem
                size="300"
                variant="Surface"
                radii="300"
                before={<Icon size="100" src={Icons.User} />}
                onClick={handleViewProfile}
              >
                <Text size="B300">View profile</Text>
              </MenuItem>
            </Box>
          </Menu>
        </FocusTrap>
      }
    >
      {/* PopOut requires a JSX child even if we anchor externally */}
      <span />
    </PopOut>
  );
}

type MemberGlanceProps = {
  room: Room;
  members: CallMembership[];
  speakers: Set<string>;
  callEmbed?: CallEmbed;
  max?: number;
};
export function MemberGlance({ room, members, speakers, callEmbed, max = 6 }: MemberGlanceProps) {
  const mx = useMatrixClient();
  const useAuthentication = useMediaAuthentication();

  const [menuState, setMenuState] = useState<{
    anchor: RectCords;
    profileCords: DOMRect;
    userId: string;
    name: string;
  } | null>(null);

  const visibleMembers = members.slice(0, max);
  const remainingCount = max && members.length > max ? members.length - max : 0;

  return (
    <>
      <Box alignItems="Center">
        {visibleMembers.map((callMember) => {
          const { userId } = callMember;
          if (!userId) return null;
          const name = getMemberDisplayName(room, userId) ?? getMxIdLocalPart(userId) ?? userId;
          const avatarMxc = getMemberAvatarMxc(room, userId);
          const avatarUrl = avatarMxc
            ? (mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96) ?? undefined)
            : undefined;

          return (
            <StackedAvatar
              key={callMember.memberId}
              className={speakers.has(callMember.sender) ? css.SpeakerAvatarOutline : undefined}
              title={name}
              as="button"
              variant="Background"
              size="200"
              radii="Pill"
              onClick={(evt) => {
                const rect = evt.currentTarget.getBoundingClientRect();
                setMenuState({
                  anchor: rect,
                  profileCords: rect,
                  userId,
                  name,
                });
              }}
            >
              <UserAvatar
                userId={userId}
                src={avatarUrl}
                alt={name}
                renderFallback={() => <Icon size="50" src={Icons.User} filled />}
              />
            </StackedAvatar>
          );
        })}
        {remainingCount > 0 && (
          <Text size="L400" style={{ paddingLeft: config.space.S100 }}>
            +{remainingCount}
          </Text>
        )}
      </Box>

      {menuState && (
        <ParticipantMenu
          anchor={menuState.anchor}
          profileCords={menuState.profileCords}
          name={menuState.name}
          userId={menuState.userId}
          room={room}
          callEmbed={callEmbed}
          onClose={() => setMenuState(null)}
        />
      )}
    </>
  );
}
