import type { FC } from '../../lib/teact/teact';
import React, {
  memo,
  useEffect,
  useMemo,
  useState,
} from '../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../global';

import type { ApiChat, ApiChatMember } from '../../api/types';
import type { IRadioOption } from '../ui/CheckboxGroup';

import {
  getHasAdminRight,
  getPrivateChatUserId,
  getUserFirstOrLastName,
  getUserFullName,
  isChatBasicGroup, isChatChannel,
  isChatSuperGroup,
  isUserId,
} from '../../global/helpers';
import {
  getSendersFromSelectedMessages,
  selectCanDeleteSelectedMessages,
  selectChatFullInfo,
  selectCurrentChat,
  selectCurrentMessageIds,
  selectCurrentMessageList,
  selectSenderFromMessage,
  selectTabState,
  selectUser,
} from '../../global/selectors';
import buildClassName from '../../util/buildClassName';
import { buildCollectionByCallback } from '../../util/iteratees';
import { MEMO_EMPTY_ARRAY } from '../../util/memo';
import renderText from '../common/helpers/renderText';

import useLang from '../../hooks/useLang';
import useLastCallback from '../../hooks/useLastCallback';
import useOldLang from '../../hooks/useOldLang';
import usePreviousDeprecated from '../../hooks/usePreviousDeprecated';
import useManagePermissions from '../right/hooks/useManagePermissions';

import Avatar from '../common/Avatar';
import AvatarList from '../common/AvatarList';
import Icon from '../common/icons/Icon';
import PermissionCheckboxList from '../main/PermissionCheckboxList';
import Button from '../ui/Button';
import CheckboxGroup from '../ui/CheckboxGroup';
import ListItem from '../ui/ListItem';
import Modal from '../ui/Modal';

import styles from './DeleteSelectedMessageModal.module.scss';

export type OwnProps = {
  isOpen: boolean;
  isSchedule: boolean;
  onClose: () => void;
};

type StateProps = {
  chat?: ApiChat;
  isGroup?: boolean;
  isChannel?: boolean;
  isSuperGroup?: boolean;
  selectedMessageIds?: number[];
  canDeleteForAll?: boolean;
  contactName?: string;
  currentUserId?: string;
  willDeleteForCurrentUserOnly?: boolean;
  willDeleteForAll?: boolean;
  messageIds: number[] | undefined;
  adminMembersById?: Record<string, ApiChatMember>;
  canBanUsers?: boolean;
};

const DeleteSelectedMessageModal: FC<OwnProps & StateProps> = ({
  chat,
  isChannel,
  isGroup,
  isSuperGroup,
  isOpen,
  isSchedule,
  currentUserId,
  selectedMessageIds,
  canDeleteForAll,
  contactName,
  willDeleteForCurrentUserOnly,
  willDeleteForAll,
  messageIds,
  onClose,
  adminMembersById,
  canBanUsers,
}) => {
  const {
    deleteMessages,
    reportChannelSpam,
    deleteChatMember,
    deleteScheduledMessages,
    exitMessageSelectMode,
    updateChatMemberBannedRights,
  } = getActions();

  const prevIsOpen = usePreviousDeprecated(isOpen);

  const oldLang = useOldLang();
  const lang = useLang();

  const {
    permissions, havePermissionChanged, handlePermissionChange, resetPermissions,
  } = useManagePermissions(chat?.defaultBannedRights);

  const [chosenDeleteOption, setChosenDeleteOption] = useState<string[] | undefined>(undefined);
  const [chosenBanOption, setChosenBanOptions] = useState<string[] | undefined>(undefined);
  const [chosenSpanOption, setChosenSpanOptions] = useState<string[] | undefined>(undefined);
  const [isMediaDropdownOpen, setIsMediaDropdownOpen] = useState(false);
  const [isAdditionalOptionsVisible, setIsAdditionalOptionsVisible] = useState(false);

  const senderList = useMemo(() => {
    if (isChannel) {
      return undefined;
    }
    const senderArray = getSendersFromSelectedMessages(getGlobal(), chat);
    return senderArray?.filter(Boolean);
    // eslint-disable-next-line react-hooks-static-deps/exhaustive-deps
  }, [chat, isChannel, isOpen]);

  const isSenderOwner = useMemo(() => {
    if (!senderList) {
      return undefined;
    }

    return senderList.some((sender) => sender
      && adminMembersById
      && adminMembersById[sender.id] && adminMembersById[sender.id].isOwner);
  }, [senderList, adminMembersById]);

  const userList = useMemo(() => {
    const usersById = getGlobal().users.byId;
    if (!senderList || isSchedule) return [];
    const uniqueUserIds = new Set(senderList.map((user) => user!.id));

    return Array.from(uniqueUserIds)
      .map((id) => usersById[id])
      .filter(Boolean);
  }, [isSchedule, senderList]);

  const nestedOptionsWithAvatarList = useLastCallback(() => {
    return userList.map((user) => ({
      value: `${user.id}`,
      label: getUserFullName(user) || '',
      leftElement: <Avatar size="small" peer={user} />,
    }));
  });

  const showAdditionalOptions = useMemo(() => {
    return !userList.some((user) => user.id === currentUserId);
  }, [userList, currentUserId]);

  const shouldShowOptions = showAdditionalOptions && !canDeleteForAll && !isSchedule && (isGroup || isSuperGroup);

  const userNames = useMemo(() => {
    const usersById = getGlobal().users.byId;
    if (!senderList || isSchedule) return {};

    const uniqueUserIds = new Set(senderList.map((user) => user!.id));
    const userIds = Array.from(uniqueUserIds).map((userId) => usersById[userId]);

    return buildCollectionByCallback(userIds, (user) => [user?.id, getUserFullName(user)]);
  }, [isSchedule, senderList]);

  const ACTION_SPAM_OPTION: IRadioOption[] = useMemo(() => {
    return [
      {
        value: selectedMessageIds && userList.length >= 2 ? 'spam' : userList?.[0]?.id,
        label: oldLang('ReportSpamTitle'),
        nestedOptions: selectedMessageIds && userList.length >= 2 ? [
          ...nestedOptionsWithAvatarList(),
        ] : undefined,
      },
    ];
  }, [oldLang, selectedMessageIds, userList]);

  const ACTION_DELETE_OPTION: IRadioOption[] = useMemo(() => {
    return [
      {
        value: selectedMessageIds && userList.length >= 2 ? 'delete_all' : userList?.[0]?.id,
        label: selectedMessageIds && userList.length >= 2
          ? oldLang('DeleteAllFromUsers')
          : oldLang('DeleteAllFrom', Object.values(userNames)[0]),
        nestedOptions: selectedMessageIds && userList.length >= 2 ? [
          ...nestedOptionsWithAvatarList(),
        ] : undefined,
      },
    ];
  }, [oldLang, selectedMessageIds, userList, userNames]);

  const ACTION_BAN_OPTION: IRadioOption[] = useMemo(() => {
    return [
      {
        value: selectedMessageIds && userList.length >= 2 ? 'ban' : userList?.[0]?.id,
        label: selectedMessageIds && userList.length >= 2
          ? (isAdditionalOptionsVisible ? oldLang('DeleteRestrictUsers') : oldLang('DeleteBanUsers'))
          : (isAdditionalOptionsVisible ? oldLang('KickFromSupergroup')
            : oldLang('DeleteBan', Object.values(userNames)[0])),
        nestedOptions: selectedMessageIds && userList.length >= 2 ? [
          ...nestedOptionsWithAvatarList(),
        ] : undefined,
      },
    ];
  }, [isAdditionalOptionsVisible, oldLang, selectedMessageIds, userList, userNames]);

  const toggleAdditionalOptions = useLastCallback(() => {
    setIsAdditionalOptionsVisible((prev) => !prev);
  });

  const handleDeleteMessageForAll = useLastCallback(() => {
    onClose();
    deleteMessages({ messageIds: selectedMessageIds!, shouldDeleteForAll: true });
  });

  const filterMessageIdByUserId = useLastCallback((userIds: string[], selectedMessageIdList: number[]) => {
    if (!chat) return MEMO_EMPTY_ARRAY;
    return selectedMessageIdList.filter((msgId) => {
      const sender = selectSenderFromMessage(getGlobal(), chat.id, msgId);
      return sender && userIds.includes(sender.id);
    });
  });

  const handleReportSpam = useLastCallback((userMessagesMap: Record<string, number[]>) => {
    Object.entries(userMessagesMap).forEach(([userId, messageIdList]) => {
      if (messageIdList.length) {
        reportChannelSpam({
          participantId: userId,
          chatId: chat!.id,
          messageIds: messageIdList,
        });
      }
    });
  });

  const handleDeleteMessages = useLastCallback((filteredMessageIdList: number[]) => {
    if (filteredMessageIdList && filteredMessageIdList.length) {
      deleteMessages({ messageIds: filteredMessageIdList, shouldDeleteForAll: true });
    }
  });

  const handleDeleteMember = useLastCallback((filteredUserIdList: string[]) => {
    filteredUserIdList.forEach((userId) => {
      deleteChatMember({ chatId: chat!.id, userId });
    });
  });

  const handleUpdateChatMemberBannedRights = useLastCallback((filteredUserIdList: string[]) => {
    filteredUserIdList.forEach((userId) => {
      updateChatMemberBannedRights({
        chatId: chat!.id,
        userId,
        bannedRights: permissions,
      });
    });
  });

  const handleDeleteMessageForSelf = useLastCallback(() => {
    if (!chat) return;

    if (isSchedule) {
      deleteScheduledMessages({ messageIds: selectedMessageIds! });
    } else if (!isSenderOwner && shouldShowOptions) {
      if (chosenSpanOption) {
        const userIdList = chosenSpanOption.filter((option) => !Number.isNaN(Number(option)));
        const userMessagesMap = selectedMessageIds!.reduce<Record<string, number[]>>((acc, msgId) => {
          const sender = selectSenderFromMessage(getGlobal(), chat.id, msgId);
          if (sender && userIdList.includes(sender.id)) {
            if (!acc[sender.id]) {
              acc[sender.id] = [];
            }
            acc[sender.id].push(Number(msgId));
          }
          return acc;
        }, {});

        handleReportSpam(userMessagesMap);
      }

      if (chosenDeleteOption) {
        const userIdList = chosenDeleteOption.filter((option) => !Number.isNaN(Number(option)));
        const filteredMessageIdList = filterMessageIdByUserId(userIdList, messageIds!);
        handleDeleteMessages(filteredMessageIdList);
      }

      if (chosenBanOption && !havePermissionChanged) {
        const userIdList = chosenBanOption.filter((option) => !Number.isNaN(Number(option)));
        const filteredUserIdList = userIdList.filter((userId) => selectedMessageIds?.some((msgId) => {
          const sender = selectSenderFromMessage(getGlobal(), chat.id, msgId);
          return sender && sender.id === userId;
        }));
        handleDeleteMember(filteredUserIdList);
        const filteredMessageIdList = filterMessageIdByUserId(userIdList, selectedMessageIds!);
        handleDeleteMessages(filteredMessageIdList);
      }

      if (chosenBanOption && havePermissionChanged) {
        const userIdList = chosenBanOption.filter((option) => !Number.isNaN(Number(option)));
        const filteredUserIdList = userIdList.filter((userId) => selectedMessageIds?.some((msgId) => {
          const sender = selectSenderFromMessage(getGlobal(), chat.id, msgId);
          return sender && sender.id === userId;
        }));
        handleUpdateChatMemberBannedRights(filteredUserIdList);
      }
    } else {
      deleteMessages({ messageIds: selectedMessageIds!, shouldDeleteForAll: false });
    }

    onClose();
  });

  const onCloseHandler = useLastCallback(() => {
    onClose();
  });

  const handleDeleteOptionChange = useLastCallback((options: string[]) => {
    setChosenDeleteOption(options);
  });

  const handleBanOptionChange = useLastCallback((options: string[]) => {
    setChosenBanOptions(options);
  });

  const handleSpanOptionChange = useLastCallback((options: string[]) => {
    setChosenSpanOptions(options);
  });

  useEffect(() => {
    if (!isOpen && prevIsOpen) {
      exitMessageSelectMode();
      setChosenSpanOptions(undefined);
      setChosenDeleteOption(undefined);
      setChosenBanOptions(undefined);
      setIsMediaDropdownOpen(false);
      setIsAdditionalOptionsVisible(false);
      resetPermissions();
    }
  }, [exitMessageSelectMode, isOpen, prevIsOpen, resetPermissions]);

  function renderHeader() {
    return (
      <div
        className={shouldShowOptions && styles.container}
        dir={oldLang.isRtl ? 'rtl' : undefined}
      >
        {shouldShowOptions && (
          <AvatarList
            size="small"
            peers={userList}
          />
        )}
        <h3 className={buildClassName(shouldShowOptions ? styles.title : styles.singleTitle)}>
          {oldLang('Chat.DeleteMessagesConfirmation', selectedMessageIds?.length)}
        </h3>
      </div>
    );
  }

  function renderAdditionalActionOptions() {
    return (
      <div className={styles.options}>
        <CheckboxGroup
          options={ACTION_SPAM_OPTION}
          onChange={handleSpanOptionChange}
          selected={chosenSpanOption}
          nestedCheckbox={selectedMessageIds && userList.length >= 2}
        />
        <CheckboxGroup
          options={ACTION_DELETE_OPTION}
          onChange={handleDeleteOptionChange}
          selected={chosenDeleteOption}
          nestedCheckbox={selectedMessageIds && userList.length >= 2}
        />
        {!isSenderOwner && canBanUsers && (
          <CheckboxGroup
            options={ACTION_BAN_OPTION}
            onChange={handleBanOptionChange}
            selected={chosenBanOption}
            nestedCheckbox={selectedMessageIds && userList.length >= 2}
          />
        )}
      </div>
    );
  }

  function renderPartiallyRestrictedUser() {
    return (
      <div className={buildClassName(styles.restrictionContainer,
        isAdditionalOptionsVisible && styles.restrictionContainerOpen)}
      >
        <h3 className={buildClassName(styles.actionTitle, styles.restrictionTitle)}>
          {oldLang('UserRestrictionsCanDoUsers', userList.length)}
        </h3>
        <PermissionCheckboxList
          withCheckbox
          permissionGroup
          chatId={chat?.id}
          isMediaDropdownOpen={isMediaDropdownOpen}
          setIsMediaDropdownOpen={setIsMediaDropdownOpen}
          handlePermissionChange={handlePermissionChange}
          permissions={permissions}
          className={buildClassName(styles.dropdownList, isMediaDropdownOpen && styles.dropdownListOpen)}
        />
      </div>
    );
  }

  if (!selectedMessageIds) {
    return undefined;
  }

  return (
    <Modal
      isOpen={isOpen}
      onClose={onClose}
      onEnter={canDeleteForAll ? undefined : handleDeleteMessageForSelf}
      className="delete"
    >
      <div className={styles.main}>
        {renderHeader()}
        {!showAdditionalOptions && <p>{lang('AreYouSureDeleteFewMessages')}</p>}
        {shouldShowOptions && (
          <>
            <p className={styles.actionTitle}>{oldLang('DeleteAdditionalActions')}</p>
            {renderAdditionalActionOptions()}
            {renderPartiallyRestrictedUser()}
            {
              chosenBanOption && canBanUsers && chosenBanOption?.length ? (
                <ListItem
                  narrow
                  className={styles.listItemButton}
                  buttonClassName={styles.button}
                  onClick={toggleAdditionalOptions}
                >
                  {oldLang(isAdditionalOptionsVisible ? 'DeleteToggleBanUsers' : 'DeleteToggleRestrictUsers')}
                  <Icon
                    name={isAdditionalOptionsVisible ? 'up' : 'down'}
                    className={buildClassName(styles.button, 'ml-2')}
                  />
                </ListItem>
              ) : setIsAdditionalOptionsVisible(false)
            }
          </>
        )}
        {willDeleteForCurrentUserOnly && lang('DeleteForMeDescription')}
        {(willDeleteForAll && !showAdditionalOptions) && lang('DeleteForEveryoneDescription')}
        <div className={canDeleteForAll ? 'dialog-buttons-column'
          : buildClassName('dialog-buttons', isAdditionalOptionsVisible && styles.dialogButtons)}
        >
          {canDeleteForAll && (
            <Button color="danger" className="confirm-dialog-button" isText onClick={handleDeleteMessageForAll}>
              {contactName
                ? renderText(oldLang('ChatList.DeleteForEveryone', contactName))
                : oldLang('Conversation.DeleteMessagesForEveryone')}
            </Button>
          )}
          <Button color="danger" className="confirm-dialog-button" isText onClick={handleDeleteMessageForSelf}>
            {oldLang(canDeleteForAll ? 'ChatList.DeleteForCurrentUser' : 'Delete')}
          </Button>
          <Button className="confirm-dialog-button" isText onClick={onCloseHandler}>{oldLang('Cancel')}</Button>
        </div>
      </div>
    </Modal>
  );
};

export default memo(withGlobal<OwnProps>(
  (global, { isSchedule }): StateProps => {
    const { messageIds: selectedMessageIds } = selectTabState(global).selectedMessages || {};
    const { canDeleteForAll } = selectCanDeleteSelectedMessages(global);
    const chat = selectCurrentChat(global);
    const chatFullInfo = chat && selectChatFullInfo(global, chat.id);
    const { threadId, type } = selectCurrentMessageList(global) || {};
    const messageIds = chat && selectCurrentMessageIds(global, chat.id, threadId!, type!);
    const isChannel = Boolean(chat) && isChatChannel(chat);
    const isGroup = Boolean(chat) && isChatBasicGroup(chat);
    const isSuperGroup = Boolean(chat) && isChatSuperGroup(chat);
    const contactName = chat && isUserId(chat.id)
      ? getUserFirstOrLastName(selectUser(global, getPrivateChatUserId(chat)!))
      : undefined;
    const adminMembersById = chatFullInfo?.adminMembersById;
    const canBanUsers = chat && (chat.isCreator || getHasAdminRight(chat, 'banUsers'));
    const willDeleteForCurrentUserOnly = chat && isChatBasicGroup(chat) && !canDeleteForAll;
    const willDeleteForAll = chat && isChatSuperGroup(chat);

    return {
      chat,
      isGroup,
      isChannel,
      isSuperGroup,
      selectedMessageIds,
      currentUserId: global.currentUserId,
      canDeleteForAll: !isSchedule && canDeleteForAll,
      contactName,
      willDeleteForCurrentUserOnly,
      willDeleteForAll,
      messageIds,
      adminMembersById,
      canBanUsers,
    };
  },
)(DeleteSelectedMessageModal));
