import { isEmpty, isEqual } from 'lodash';
import { useEffect, useMemo, useState } from 'react';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { Data } from '../../data/data';
import { useMessageReactsPropsById } from '../../hooks/useParamSelector';
import { isUsAnySogsFromCache } from '../../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import { UserUtils } from '../../session/utils';
import {
  updateReactClearAllModal,
  updateReactListModal,
  updateUserDetailsModal,
} from '../../state/ducks/modalDialog';
import {
  useSelectedIsPublic,
  useSelectedWeAreAdmin,
  useSelectedWeAreModerator,
} from '../../state/selectors/selectedConversation';
import { SortedReactionList } from '../../types/Reaction';
import { nativeEmojiData } from '../../util/emoji';
import { Reactions } from '../../util/reactions';
import { Avatar, AvatarSize } from '../avatar/Avatar';
import { Flex } from '../basic/Flex';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { ContactName } from '../conversation/ContactName';
import { MessageReactions } from '../conversation/message/message-content/MessageReactions';
import { SessionIconButton } from '../icon';
import { SessionWrapperModal } from '../SessionWrapperModal';
import { findAndFormatContact } from '../../models/message';
import { Localizer } from '../basic/Localizer';

const StyledReactListContainer = styled(Flex)`
  width: 376px;
`;

const StyledReactionsContainer = styled.div`
  background-color: var(--modal-background-content-color);
  border-bottom: 1px solid var(--border-color);
  width: 100%;
  overflow-x: auto;
  padding: 12px 8px 0;
`;

const StyledSendersContainer = styled(Flex)`
  width: 100%;
  min-height: 332px;
  height: 100%;
  max-height: 496px;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 0 16px 16px;
`;

const StyledContactContainer = styled.span`
  text-overflow: ellipsis;
  overflow: hidden;
`;

const StyledReactionBar = styled(Flex)`
  width: 100%;
  margin: 12px 0 20px 4px;

  p {
    color: var(--text-secondary-color);
    margin: 0;

    span:nth-child(1) {
      margin: 0 8px;
      color: var(--text-primary-color);
      white-space: nowrap;
    }

    span:nth-child(2) {
      margin-right: 8px;
    }
  }

  .session-button {
    font-weight: 400;
    padding: 0px;
  }
`;

const StyledReactionSender = styled(Flex)`
  width: 100%;
  margin-bottom: 12px;

  .module-avatar {
    margin-right: 12px;
  }

  .module-conversation__user__profile-name {
    color: var(--text-primary-color);
    font-weight: normal;
  }
`;

type ReactionSendersProps = {
  messageId: string;
  currentReact: string;
  senders: Array<string>;
  me: string;
  handleClose: () => void;
};

const ReactionSenders = (props: ReactionSendersProps) => {
  const { messageId, currentReact, senders, me, handleClose } = props;
  const dispatch = useDispatch();

  const handleAvatarClick = async (sender: string) => {
    const message = await Data.getMessageById(messageId);
    if (message) {
      handleClose();
      const contact = findAndFormatContact(sender);
      dispatch(
        updateUserDetailsModal({
          conversationId: sender,
          userName: contact.name || contact.profileName || sender,
          authorAvatarPath: contact.avatarPath,
        })
      );
    }
  };

  const handleRemoveReaction = async () => {
    await Reactions.sendMessageReaction(messageId, currentReact);

    if (senders.length <= 1) {
      dispatch(updateReactListModal(null));
    }
  };

  return (
    <>
      {senders.map((sender: string) => (
        <StyledReactionSender
          key={`${messageId}-${sender}`}
          container={true}
          justifyContent={'space-between'}
          alignItems={'center'}
        >
          <Flex container={true} alignItems={'center'} style={{ overflow: 'hidden' }}>
            <Avatar
              size={AvatarSize.XS}
              pubkey={sender}
              onAvatarClick={() => {
                void handleAvatarClick(sender);
              }}
            />
            {sender === me ? (
              window.i18n('you')
            ) : (
              <StyledContactContainer>
                <ContactName
                  pubkey={sender}
                  module="module-conversation__user"
                  shouldShowPubkey={false}
                />
              </StyledContactContainer>
            )}
          </Flex>
          {sender === me && (
            <SessionIconButton
              iconType="exit"
              iconSize="small"
              onClick={() => {
                void handleRemoveReaction();
              }}
            />
          )}
        </StyledReactionSender>
      ))}
    </>
  );
};

const StyledCountText = styled.p`
  color: var(--text-secondary-color);
  text-align: center;
  margin: 16px auto 0;

  span {
    color: var(--text-primary);
  }
`;

const CountText = ({ count, emoji }: { count: number; emoji: string }) => {
  return (
    <StyledCountText>
      <Localizer
        token="emojiReactsCountOthers"
        args={{
          count: count - Reactions.SOGSReactorsFetchCount,
          emoji,
        }}
      />
    </StyledCountText>
  );
};

type Props = {
  reaction: string;
  messageId: string;
};

const handleSenders = (senders: Array<string>, me: string) => {
  let updatedSenders = [...senders];
  const blindedMe = updatedSenders.filter(isUsAnySogsFromCache);

  let meIndex = -1;
  if (blindedMe && blindedMe[0]) {
    meIndex = updatedSenders.indexOf(blindedMe[0]);
  } else {
    meIndex = updatedSenders.indexOf(me);
  }
  if (meIndex >= 0) {
    updatedSenders.splice(meIndex, 1);
    updatedSenders = [me, ...updatedSenders];
  }

  return updatedSenders;
};

export const ReactListModal = (props: Props) => {
  const { reaction, messageId } = props;

  const dispatch = useDispatch();
  const [reactions, setReactions] = useState<SortedReactionList>([]);

  const [currentReact, setCurrentReact] = useState('');
  const [reactAriaLabel, setReactAriaLabel] = useState<string | undefined>();
  const [count, setCount] = useState<number | null>(null);
  const [senders, setSenders] = useState<Array<string>>([]);

  const msgProps = useMessageReactsPropsById(messageId);
  const isPublic = useSelectedIsPublic();
  const weAreAdmin = useSelectedWeAreAdmin();
  const weAreModerator = useSelectedWeAreModerator();
  const me = UserUtils.getOurPubKeyStrFromCache();

  const reactionsMap = useMemo(() => {
    return (reactions && Object.fromEntries(reactions)) || {};
  }, [reactions]);
  const reactionsCount = reactionsMap[currentReact]?.count;

  // TODO we should break down this useEffect, it is hard to read.
  useEffect(() => {
    if (currentReact === '' && currentReact !== reaction) {
      setReactAriaLabel(
        nativeEmojiData?.ariaLabels ? nativeEmojiData.ariaLabels[reaction] : undefined
      );
      setCurrentReact(reaction);
    }

    if (msgProps?.sortedReacts && !isEqual(reactions, msgProps?.sortedReacts)) {
      setReactions(msgProps?.sortedReacts);
    }

    if (
      reactions &&
      reactions.length > 0 &&
      ((msgProps?.sortedReacts && msgProps.sortedReacts.length === 0) ||
        msgProps?.sortedReacts === undefined)
    ) {
      setReactions([]);
    }

    let _senders =
      reactionsMap && reactionsMap[currentReact] && reactionsMap[currentReact].senders
        ? reactionsMap[currentReact].senders
        : null;

    if (_senders && !isEqual(senders, _senders)) {
      if (_senders.length > 0) {
        _senders = handleSenders(_senders, me);
      }

      // make sure to deep compare here otherwise we get stuck in a ever rendering look (only happens when we are one of the reactor)
      if (!isEqual(_senders, senders)) {
        setSenders(_senders);
      }
    }

    if (senders.length > 0 && (!reactionsMap[currentReact]?.senders || isEmpty(_senders))) {
      setSenders([]);
    }

    if (reactionsCount && count !== reactionsCount) {
      setCount(reactionsMap[currentReact].count);
    }
  }, [
    count,
    currentReact,
    me,
    reaction,
    reactionsCount,
    msgProps?.sortedReacts,
    reactionsMap,
    senders,
    reactions,
  ]);

  if (!msgProps) {
    return <></>;
  }

  const handleSelectedReaction = (emoji: string): boolean => {
    return currentReact === emoji;
  };

  const handleReactionClick = (emoji: string) => {
    setReactAriaLabel(nativeEmojiData?.ariaLabels ? nativeEmojiData.ariaLabels[emoji] : undefined);
    setCurrentReact(emoji);
  };

  const handleClose = () => {
    dispatch(updateReactListModal(null));
  };

  const handleClearReactions = () => {
    handleClose();
    dispatch(
      updateReactClearAllModal({
        reaction: currentReact,
        messageId,
      })
    );
  };

  return (
    <SessionWrapperModal
      additionalClassName={'reaction-list-modal no-body-padding'}
      showHeader={false}
      onClose={handleClose}
    >
      <StyledReactListContainer container={true} flexDirection={'column'} alignItems={'flex-start'}>
        <StyledReactionsContainer>
          <MessageReactions
            messageId={messageId}
            hasReactLimit={false}
            inModal={true}
            onSelected={handleSelectedReaction}
            onClick={handleReactionClick}
            noAvatar={true}
          />
        </StyledReactionsContainer>
        {reactionsMap && currentReact && (
          <StyledSendersContainer
            container={true}
            flexDirection={'column'}
            alignItems={'flex-start'}
          >
            <StyledReactionBar
              container={true}
              justifyContent={'space-between'}
              alignItems={'center'}
            >
              <p>
                <span role={'img'} aria-label={reactAriaLabel}>
                  {currentReact}
                </span>
                {reactionsMap[currentReact].count && (
                  <>
                    <span>&#8226;</span>
                    <span>{reactionsMap[currentReact].count}</span>
                  </>
                )}
              </p>
              {isPublic && (weAreAdmin || weAreModerator) && (
                <SessionButton
                  text={window.i18n('clearAll')}
                  buttonColor={SessionButtonColor.Danger}
                  buttonType={SessionButtonType.Simple}
                  onClick={handleClearReactions}
                />
              )}
            </StyledReactionBar>
            {senders && senders.length > 0 && (
              <ReactionSenders
                messageId={messageId}
                currentReact={currentReact}
                senders={senders}
                me={me}
                handleClose={handleClose}
              />
            )}
            {isPublic && currentReact && count && count > Reactions.SOGSReactorsFetchCount && (
              <CountText count={count} emoji={currentReact} />
            )}
          </StyledSendersContainer>
        )}
      </StyledReactListContainer>
    </SessionWrapperModal>
  );
};