import React, { useMemo } from 'react';
import { Box, Icon, IconButton, Icons, Text, as } from 'folds';
import { Room } from 'matrix-js-sdk';
import classNames from 'classnames';
import { useSetAtom } from 'jotai';
import { roomIdToTypingMembersAtom } from '../../state/typingMembers';
import { TypingIndicator } from '../../components/typing-indicator';
import { getMemberDisplayName } from '../../utils/room';
import { getMxIdLocalPart } from '../../utils/matrix';
import * as css from './RoomViewTyping.css';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useRoomTypingMember } from '../../hooks/useRoomTypingMembers';

export type RoomViewTypingProps = {
  room: Room;
};
export const RoomViewTyping = as<'div', RoomViewTypingProps>(
  ({ className, room, ...props }, ref) => {
    const setTypingMembers = useSetAtom(roomIdToTypingMembersAtom);
    const mx = useMatrixClient();
    const typingMembers = useRoomTypingMember(room.roomId);

    const myUserId = mx.getUserId();
    const typingNames = useMemo(
      () =>
        typingMembers
          .filter((receipt) => receipt.userId !== myUserId)
          .map(
            (receipt) =>
              getMemberDisplayName(room, receipt.userId) ?? getMxIdLocalPart(receipt.userId),
          )
          .reverse(),
      [typingMembers, myUserId, room],
    );

    // A single, non-truncated string for assistive technology to announce.
    // Computed even when empty so the live region can stay mounted (below) —
    // a `role="status"` region added to the DOM together with its first text
    // is not reliably announced by some screen readers.
    let typingAnnouncement = '';
    if (typingNames.length === 1) {
      typingAnnouncement = `${typingNames[0]} is typing`;
    } else if (typingNames.length === 2) {
      typingAnnouncement = `${typingNames[0]} and ${typingNames[1]} are typing`;
    } else if (typingNames.length === 3) {
      typingAnnouncement = `${typingNames[0]}, ${typingNames[1]} and ${typingNames[2]} are typing`;
    } else {
      typingAnnouncement = `${typingNames[0]}, ${typingNames[1]}, ${typingNames[2]} and ${
        typingNames.length - 3
      } others are typing`;
    }

    const handleDropAll = () => {
      // some homeserver does not timeout typing status
      // we have given option so user can drop their typing status
      typingMembers.forEach((receipt) =>
        setTypingMembers({
          type: 'DELETE',
          roomId: room.roomId,
          userId: receipt.userId,
        }),
      );
    };

    return (
      <div style={{ position: 'relative' }}>
        {/* Persistently mounted so the FIRST "X is typing" is announced. */}
        <span className={css.SrOnly} role="status" aria-live="polite" aria-atomic="true">
          {typingAnnouncement}
        </span>
        {typingNames.length > 0 && (
          <Box
            className={classNames(css.RoomViewTyping, className)}
            alignItems="Center"
            gap="400"
            {...props}
            ref={ref}
          >
            <TypingIndicator />
            <Text className={css.TypingText} size="T300" truncate aria-hidden>
              {typingNames.length === 1 && (
                <>
                  <b>{typingNames[0]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {' is typing...'}
                  </Text>
                </>
              )}
              {typingNames.length === 2 && (
                <>
                  <b>{typingNames[0]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {' and '}
                  </Text>
                  <b>{typingNames[1]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {' are typing...'}
                  </Text>
                </>
              )}
              {typingNames.length === 3 && (
                <>
                  <b>{typingNames[0]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {', '}
                  </Text>
                  <b>{typingNames[1]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {' and '}
                  </Text>
                  <b>{typingNames[2]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {' are typing...'}
                  </Text>
                </>
              )}
              {typingNames.length > 3 && (
                <>
                  <b>{typingNames[0]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {', '}
                  </Text>
                  <b>{typingNames[1]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {', '}
                  </Text>
                  <b>{typingNames[2]}</b>
                  <Text as="span" size="Inherit" priority="300">
                    {' and '}
                  </Text>
                  <b>{typingNames.length - 3} others</b>
                  <Text as="span" size="Inherit" priority="300">
                    {' are typing...'}
                  </Text>
                </>
              )}
            </Text>
            <IconButton
              title="Drop Typing Status"
              aria-label="Drop typing status"
              size="300"
              radii="Pill"
              onClick={handleDropAll}
            >
              <Icon size="50" src={Icons.Cross} />
            </IconButton>
          </Box>
        )}
      </div>
    );
  },
);
