import { memo, useMemo, useRef, useState } from '../../../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../../../global';

import type {
  ApiEmojiStatusType,
  ApiPeer,
  ApiUser,
} from '../../../../api/types';
import type { TabState } from '../../../../global/types';

import { STARS_CURRENCY_CODE, TON_CURRENCY_CODE } from '../../../../config';
import { getHasAdminRight } from '../../../../global/helpers';
import { getPeerTitle, isApiPeerChat, isApiPeerUser } from '../../../../global/helpers/peers';
import { getMainUsername } from '../../../../global/helpers/users';
import { selectPeer, selectUser } from '../../../../global/selectors';
import buildClassName from '../../../../util/buildClassName';
import { copyTextToClipboard } from '../../../../util/clipboard';
import { formatDateTimeToString } from '../../../../util/dates/dateFormat';
import { formatCurrencyAsString } from '../../../../util/formatCurrency';
import {
  formatStarsAsIcon, formatStarsAsText, formatTonAsIcon, formatTonAsText,
} from '../../../../util/localization/format';
import { CUSTOM_PEER_HIDDEN } from '../../../../util/objects/customPeer';
import { getServerTime } from '../../../../util/serverTime';
import { formatPercent } from '../../../../util/textFormat';
import { renderGiftOriginalInfo } from '../../../common/helpers/giftOriginalInfo';
import { getGiftAttributes, getStickerFromGift } from '../../../common/helpers/gifts';
import { renderTextWithEntities } from '../../../common/helpers/renderTextWithEntities';

import useContextMenuHandlers from '../../../../hooks/useContextMenuHandlers';
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
import useFlag from '../../../../hooks/useFlag';
import useLang from '../../../../hooks/useLang';
import useLastCallback from '../../../../hooks/useLastCallback';
import useOldLang from '../../../../hooks/useOldLang';

import AnimatedIconFromSticker from '../../../common/AnimatedIconFromSticker';
import Avatar from '../../../common/Avatar';
import BadgeButton from '../../../common/BadgeButton';
import GiftMenuItems from '../../../common/gift/GiftMenuItems';
import GiftTransferPreview from '../../../common/gift/GiftTransferPreview';
import Icon from '../../../common/icons/Icon';
import SafeLink from '../../../common/SafeLink';
import Button from '../../../ui/Button';
import Checkbox from '../../../ui/Checkbox';
import ConfirmDialog from '../../../ui/ConfirmDialog';
import Link from '../../../ui/Link';
import Menu from '../../../ui/Menu';
import TableInfoModal, { type TableData } from '../../common/TableInfoModal';
import UniqueGiftHeader from '../UniqueGiftHeader';

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

export type OwnProps = {
  modal: TabState['giftInfoModal'];
};

type StateProps = {
  fromPeer?: ApiPeer;
  targetPeer?: ApiPeer;
  releasedByPeer?: ApiPeer;
  currentUserId?: string;
  starGiftMaxConvertPeriod?: number;
  hasAdminRights?: boolean;
  currentUserEmojiStatus?: ApiEmojiStatusType;
  collectibleEmojiStatuses?: ApiEmojiStatusType[];
  tonExplorerUrl?: string;
  currentUser?: ApiUser;
  recipientPeer?: ApiPeer;
};

const STICKER_SIZE = 120;

const GiftInfoModal = ({
  modal,
  fromPeer,
  targetPeer,
  releasedByPeer,
  currentUserId,
  starGiftMaxConvertPeriod,
  hasAdminRights,
  currentUserEmojiStatus,
  collectibleEmojiStatuses,
  tonExplorerUrl,
  currentUser,
  recipientPeer,
}: OwnProps & StateProps) => {
  const {
    closeGiftInfoModal,
    changeGiftVisibility,
    convertGiftToStars,
    openChatWithInfo,
    focusMessage,
    openGiftUpgradeModal,
    showNotification,
    buyStarGift,
    closeGiftModal,
    openGiftInfoValueModal,
    updateResaleGiftsFilter,
    openGiftInMarket,
    openGiftDescriptionRemoveModal,
  } = getActions();

  const [isConvertConfirmOpen, openConvertConfirm, closeConvertConfirm] = useFlag();

  const lang = useLang();
  const oldLang = useOldLang();
  const [isConfirmModalOpen, setIsConfirmModalOpen] = useState<boolean>(false);
  const [shouldPayInTon, setShouldPayInTon] = useState<boolean>(false);

  const splitButtonRef = useRef<HTMLDivElement>();
  const menuRef = useRef<HTMLDivElement>();
  const uniqueGiftHeaderRef = useRef<HTMLDivElement>();
  const {
    isContextMenuOpen,
    contextMenuAnchor,
    handleContextMenu,
    handleContextMenuClose,
    handleContextMenuHide,
  } = useContextMenuHandlers(splitButtonRef);

  const handleSymbolClick = useLastCallback(() => {
    if (!gift || !giftAttributes?.pattern) return;

    openGiftInMarket({ gift });
    updateResaleGiftsFilter({
      filter: {
        sortType: 'byDate',
        modelAttributes: [],
        backdropAttributes: [],
        patternAttributes: [{
          type: 'pattern',
          documentId: giftAttributes.pattern.sticker.id,
        }],
      },
    });
  });

  const handleBackdropClick = useLastCallback(() => {
    if (!gift || !giftAttributes?.backdrop) return;

    openGiftInMarket({ gift });
    updateResaleGiftsFilter({
      filter: {
        sortType: 'byDate',
        modelAttributes: [],
        backdropAttributes: [{
          type: 'backdrop',
          backdropId: giftAttributes.backdrop.backdropId,
        }],
        patternAttributes: [],
      },
    });
  });

  const handleModelClick = useLastCallback(() => {
    if (!gift || !giftAttributes?.model) return;

    openGiftInMarket({ gift });
    updateResaleGiftsFilter({
      filter: {
        sortType: 'byDate',
        modelAttributes: [{
          type: 'model',
          documentId: giftAttributes.model.sticker.id,
        }],
        backdropAttributes: [],
        patternAttributes: [],
      },
    });
  });

  const isOpen = Boolean(modal);
  const renderingModal = useCurrentOrPrev(modal);
  const renderingFromPeer = useCurrentOrPrev(fromPeer);
  const renderingTargetPeer = useCurrentOrPrev(targetPeer);

  const isTargetChat = renderingTargetPeer && isApiPeerChat(renderingTargetPeer);

  const { gift: typeGift } = renderingModal || {};
  const isSavedGift = typeGift && 'gift' in typeGift;
  const savedGift = isSavedGift ? typeGift : undefined;
  const isSender = savedGift?.fromId === currentUserId;
  const canConvertDifference = (savedGift && starGiftMaxConvertPeriod && (
    savedGift.date + starGiftMaxConvertPeriod - getServerTime()
  )) || 0;
  const conversionLeft = Math.ceil(canConvertDifference / 60 / 60 / 24);

  const gift = isSavedGift ? typeGift.gift : typeGift;
  const giftSticker = gift && getStickerFromGift(gift);
  const hasConvertOption = canConvertDifference > 0 && Boolean(savedGift?.starsToConvert);

  const isGiftUnique = gift && gift.type === 'starGiftUnique';
  const uniqueGift = isGiftUnique ? gift : undefined;

  const giftSubtitle = useMemo(() => {
    if (!gift || gift.type !== 'starGiftUnique') return undefined;

    if (releasedByPeer) {
      const releasedByUsername = `@${getMainUsername(releasedByPeer)}`;
      const ownerTitle = releasedByUsername || getPeerTitle(lang, releasedByPeer);
      const fallbackText = isApiPeerUser(releasedByPeer)
        ? lang('ActionFallbackUser')
        : lang('ActionFallbackChannel');

      return lang('GiftInfoCollectibleBy', {
        number: gift.number, owner: ownerTitle || fallbackText }, {
        withNodes: true,
        withMarkdown: true,
      });
    }

    return lang('GiftInfoCollectible', { number: gift.number });
  }, [gift, releasedByPeer, lang]);

  const starGiftUniqueSlug = gift?.type === 'starGiftUnique' ? gift.slug : undefined;

  const selfCollectibleStatus = useMemo(() => {
    if (!starGiftUniqueSlug) return undefined;
    return collectibleEmojiStatuses?.find((status) =>
      status.type === 'collectible' && status.slug === starGiftUniqueSlug);
  }, [starGiftUniqueSlug, collectibleEmojiStatuses]);

  const isSelfUnique = Boolean(selfCollectibleStatus);
  const canFocusUpgrade = Boolean(savedGift?.upgradeMsgId);

  const canManage = !canFocusUpgrade && savedGift?.inputGift && (
    isTargetChat ? hasAdminRights
      : gift?.type === 'starGift'
        ? renderingTargetPeer?.id === currentUserId
        : gift?.ownerId === currentUserId || isSelfUnique
  );

  function getResalePrice(isInTon?: boolean) {
    if (!isGiftUnique) return undefined;
    const amounts = gift.resellPrice;
    if (!amounts) return undefined;

    if (gift?.resaleTonOnly || isInTon) {
      return amounts.find((amount) => amount.currency === TON_CURRENCY_CODE);
    }

    return amounts.find((amount) => amount.currency === STARS_CURRENCY_CODE);
  }

  const resellPrice = getResalePrice();
  const confirmPrice = getResalePrice(shouldPayInTon);
  const canBuyGift = !isSelfUnique && gift?.type === 'starGiftUnique'
    && gift.ownerId !== currentUserId && Boolean(resellPrice);

  const giftOwnerTitle = (() => {
    if (!isGiftUnique) return undefined;
    const { ownerName, ownerId } = gift;
    const global = getGlobal(); // Peer titles do not need to be reactive
    const owner = ownerId ? selectPeer(global, ownerId) : undefined;
    return owner ? getPeerTitle(lang, owner) : ownerName;
  })();

  const handleClose = useLastCallback(() => {
    closeGiftInfoModal();
  });

  const handleFocusUpgraded = useLastCallback(() => {
    const giftChat = isSender ? renderingTargetPeer : renderingFromPeer;
    if (!savedGift?.upgradeMsgId || !giftChat) return;
    const { upgradeMsgId } = savedGift;
    focusMessage({ chatId: giftChat.id, messageId: upgradeMsgId });
    handleClose();
  });

  const handleTriggerVisibility = useLastCallback(() => {
    const { inputGift, isUnsaved } = savedGift!;
    changeGiftVisibility({ gift: inputGift!, shouldUnsave: !isUnsaved });
    handleClose();
  });

  const handleConvertToStars = useLastCallback(() => {
    const { inputGift } = savedGift!;
    convertGiftToStars({ gift: inputGift! });
    closeConvertConfirm();
    handleClose();
  });

  const handleRemoveMessage = useLastCallback(() => {
    if (!savedGift?.inputGift || !savedGift.dropOriginalDetailsStars || !gift || !giftAttributes) return;

    const { originalDetails } = giftAttributes;
    if (!originalDetails) return;

    openGiftDescriptionRemoveModal({
      gift: savedGift,
      price: savedGift.dropOriginalDetailsStars,
      details: originalDetails,
    });
  });

  const handleOpenUpgradeModal = useLastCallback(() => {
    if (!savedGift) return;
    const giftOwnerId = renderingTargetPeer?.id;
    openGiftUpgradeModal({ giftId: savedGift.gift.id, gift: savedGift, peerId: giftOwnerId });
  });

  const handleBuyGift = useLastCallback(() => {
    if (gift?.type !== 'starGiftUnique' || !getResalePrice()) return;
    setIsConfirmModalOpen(true);
  });

  const closeConfirmModal = useLastCallback(() => {
    setIsConfirmModalOpen(false);
  });

  const handleConfirmBuyGift = useLastCallback(() => {
    const peer = recipientPeer || currentUser;
    const price = getResalePrice(shouldPayInTon);
    if (!peer || !price || gift?.type !== 'starGiftUnique') return;
    closeConfirmModal();
    closeGiftModal();
    buyStarGift({ peerId: peer.id, slug: gift.slug, price });
  });

  const handleOpenValueModal = useLastCallback(() => {
    if (!gift || gift.type !== 'starGiftUnique') return;

    openGiftInfoValueModal({
      gift,
    });
  });

  const giftAttributes = useMemo(() => {
    return gift && getGiftAttributes(gift);
  }, [gift]);

  const SettingsMenuButton = useMemo(() => {
    return (
      <div
        className={buildClassName(
          styles.headerButton,
          styles.left,
        )}
        tabIndex={0}
        role="button"
        aria-haspopup="menu"
        aria-label={lang('AriaMoreButton')}
        onContextMenu={handleContextMenu}
        onClick={handleContextMenu}
      >
        <Icon
          name="more"
          className={styles.icon}
        />
      </div>
    );
  }, [lang, handleContextMenu]);

  const renderFooterButton = useLastCallback(() => {
    if (canBuyGift) {
      return (
        <Button noForcedUpperCase onClick={handleBuyGift}>
          {lang('ButtonBuyGift', {
            stars: resellPrice?.currency === TON_CURRENCY_CODE
              ? formatTonAsIcon(lang, resellPrice.amount, { shouldConvertFromNanos: true })
              : formatStarsAsIcon(lang, resellPrice?.amount, { asFont: true }),
          }, { withNodes: true })}
        </Button>
      );
    }

    if (canFocusUpgrade) {
      return (
        <Button onClick={handleFocusUpgraded}>
          {lang('GiftInfoViewUpgraded')}
        </Button>
      );
    }

    if (canManage && savedGift?.alreadyPaidUpgradeStars && !savedGift.upgradeMsgId) {
      return (
        <Button
          isShiny
          onClick={handleOpenUpgradeModal}
          iconName="arrow-down-circle"
          iconClassName={styles.upgradeIcon}
          iconAlignment="end"
        >
          {lang('GiftInfoUpgradeForFree')}
        </Button>
      );
    }

    if (canManage && savedGift?.canUpgrade && !savedGift.upgradeMsgId) {
      return (
        <Button
          isShiny
          onClick={handleOpenUpgradeModal}
          iconName="arrow-down-circle"
          iconClassName={styles.upgradeIcon}
          iconAlignment="end"
        >
          {lang('GiftInfoUpgrade')}
        </Button>
      );
    }

    if (savedGift?.prepaidUpgradeHash) {
      return (
        <Button
          isShiny
          onClick={handleOpenUpgradeModal}
          iconName="arrow-down-circle"
          iconClassName={styles.upgradeIcon}
          iconAlignment="end"
        >
          {lang('GiftAnUpgradeButton')}
        </Button>
      );
    }

    return (
      <Button onClick={handleClose}>
        {lang('OK')}
      </Button>
    );
  });

  const saleDateInfo = useMemo(() => {
    if (!gift) return undefined;
    let text = '';
    if (gift.type === 'starGift') {
      if (gift.firstSaleDate) {
        text += `${lang('GiftInfoFirstSale')} ${formatDateTimeToString(gift.firstSaleDate * 1000, lang.code, true)}`;
      }
      if (gift.lastSaleDate) {
        text += '\n';
        text += `${lang('GiftInfoLastSale')} ${formatDateTimeToString(gift.lastSaleDate * 1000, lang.code, true)}`;
      }
    }

    return text;
  }, [gift, lang]);

  const modalData = useMemo(() => {
    if (!typeGift || !gift) {
      return undefined;
    }

    const {
      fromId, isNameHidden, starsToConvert, isUnsaved, isConverted, upgradeMsgId,
    } = savedGift || {};
    const canConvert = hasConvertOption && Boolean(starsToConvert);

    const isVisibleForMe = isNameHidden && renderingTargetPeer;

    const description = (() => {
      if (!savedGift) return lang('GiftInfoSoldOutDescription');
      if (isTargetChat) return undefined;

      if (savedGift.upgradeMsgId) return lang('GiftInfoDescriptionUpgraded');
      if (canManage && savedGift.canUpgrade && savedGift.alreadyPaidUpgradeStars && !savedGift.upgradeMsgId) {
        return lang('GiftInfoDescriptionUpgrade2');
      }
      if (savedGift.canUpgrade && canManage) {
        return canManage
          ? lang('GiftInfoDescriptionFreeUpgrade')
          : lang('GiftInfoPeerDescriptionFreeUpgradeOut', { peer: getPeerTitle(lang, renderingTargetPeer!)! });
      }
      if (!canManage && !isSender) return undefined;
      if (isConverted && canConvert) {
        return canManage
          ? lang('GiftInfoDescriptionConverted', {
            amount: starsToConvert,
          }, {
            pluralValue: starsToConvert,
            withNodes: true,
            withMarkdown: true,
          })
          : lang('GiftInfoPeerDescriptionOutConverted', {
            amount: starsToConvert,
            peer: getPeerTitle(lang, renderingTargetPeer!)!,
          }, {
            pluralValue: starsToConvert,
            withNodes: true,
            withMarkdown: true,
          });
      }

      if (savedGift.canUpgrade && canManage) {
        if (canConvert) {
          return lang('GiftInfoDescriptionUpgrade', {
            amount: starsToConvert,
          }, {
            pluralValue: starsToConvert,
            withNodes: true,
            withMarkdown: true,
          });
        }

        return lang('GiftInfoDescriptionUpgradeRegular');
      }

      if (canManage) {
        if (canConvert) {
          return lang('GiftInfoDescription', {
            amount: starsToConvert,
          }, {
            withNodes: true,
            withMarkdown: true,
            pluralValue: starsToConvert,
          });
        }

        return lang('GiftInfoDescriptionRegular');
      }

      if (canConvert) {
        return lang('GiftInfoPeerDescriptionOut', {
          amount: starsToConvert,
          peer: getPeerTitle(lang, renderingTargetPeer!)!,
        }, {
          withNodes: true,
          withMarkdown: true,
          pluralValue: starsToConvert,
        });
      }

      return lang('GiftInfoPeerDescriptionOutRegular', { peer: getPeerTitle(lang, renderingTargetPeer!)! });
    })();

    function getTitle() {
      if (isGiftUnique) return gift.title;
      if (!savedGift) return lang('GiftInfoSoldOutTitle');

      return canManage ? lang('GiftInfoReceived') : lang('GiftInfoTitle');
    }

    const uniqueGiftModalHeader = (
      <div
        className={styles.modalHeader}
      >
        {Boolean(resellPrice?.amount) && (
          <div className={styles.giftResalePriceContainer}>
            {resellPrice.currency === TON_CURRENCY_CODE
              ? formatTonAsIcon(lang, resellPrice.amount, {
                className: styles.giftResalePriceStar,
                shouldConvertFromNanos: true,
              })
              : formatStarsAsIcon(lang, resellPrice.amount, {
                asFont: true,
                className: styles.giftResalePriceStar,
              })}
          </div>
        )}
        <div className={styles.headerSplitButton} ref={splitButtonRef}>
          {SettingsMenuButton}
          <div
            className={buildClassName(
              styles.headerButton,
              styles.right,
            )}
            tabIndex={0}
            role="button"
            aria-haspopup="menu"
            aria-label={lang('Close')}
            onClick={handleClose}
          >
            <Icon
              name="close"
              className={buildClassName(
                styles.icon,
                styles.moreIcon,
              )}
            />
          </div>
        </div>
      </div>
    );

    const uniqueGiftHeader = isGiftUnique && (
      <div ref={uniqueGiftHeaderRef} className={buildClassName(styles.header, styles.uniqueGift)}>
        <UniqueGiftHeader
          backdropAttribute={giftAttributes!.backdrop!}
          patternAttribute={giftAttributes!.pattern!}
          modelAttribute={giftAttributes!.model!}
          title={gift.title}
          subtitle={giftSubtitle}
          subtitlePeer={releasedByPeer}
          showManageButtons={canManage}
          savedGift={savedGift}
        />
      </div>
    );

    const regularHeader = (
      <div className={styles.header}>
        <AnimatedIconFromSticker
          className={styles.giftSticker}
          sticker={giftSticker}
          size={STICKER_SIZE}
        />
        <h1 className={styles.title}>
          {getTitle()}
        </h1>
        {Boolean(description) && (
          <p className={buildClassName(styles.description, !savedGift && gift?.type === 'starGift' && styles.soldOut)}>
            {description}
          </p>
        )}
      </div>
    );

    const tableData: TableData = [];
    if (gift.type === 'starGift') {
      const hasFrom = fromId || isNameHidden;

      if (hasFrom) {
        tableData.push([
          lang('GiftInfoFrom'),
          !fromId ? (
            <>
              <Avatar size="small" peer={CUSTOM_PEER_HIDDEN} />
              <span className={styles.unknown}>{oldLang(CUSTOM_PEER_HIDDEN.titleKey!)}</span>
            </>
          ) : { chatId: fromId },
        ]);
      }

      if (savedGift?.date) {
        tableData.push([
          lang('GiftInfoDate'),
          <span title={saleDateInfo}>{formatDateTimeToString(savedGift.date * 1000, lang.code, true)}</span>,
        ]);
      }

      if (gift.firstSaleDate && !savedGift) {
        tableData.push([
          lang('GiftInfoFirstSale'),
          formatDateTimeToString(gift.firstSaleDate * 1000, lang.code, true),
        ]);
      }

      if (gift.lastSaleDate && !savedGift) {
        tableData.push([
          lang('GiftInfoLastSale'),
          formatDateTimeToString(gift.lastSaleDate * 1000, lang.code, true),
        ]);
      }

      const starsValue = gift.stars + (savedGift?.alreadyPaidUpgradeStars || 0);

      tableData.push([
        lang('GiftInfoValue'),
        <div className={styles.giftValue}>
          {formatStarsAsIcon(lang, starsValue, { className: styles.starAmountIcon })}
          {canManage && hasConvertOption && Boolean(starsToConvert) && (
            <BadgeButton onClick={openConvertConfirm}>
              {lang('GiftInfoConvert', { amount: starsToConvert }, { pluralValue: starsToConvert })}
            </BadgeButton>
          )}
        </div>,
      ]);

      if (gift.availabilityTotal) {
        tableData.push([
          lang('GiftInfoAvailability'),
          lang('GiftInfoAvailabilityValue', {
            count: gift.availabilityRemains || 0,
            total: gift.availabilityTotal,
          }, {
            pluralValue: gift.availabilityRemains || 0,
          }),
        ]);
      }

      if (gift.upgradeStars && !upgradeMsgId) {
        tableData.push([
          lang('GiftInfoStatus'),
          <div className={styles.giftValue}>
            {lang('GiftInfoStatusNonUnique')}
          </div>,
        ]);
      }

      if (savedGift?.message) {
        tableData.push([
          undefined,
          renderTextWithEntities(savedGift.message),
        ]);
      }
    }

    if (isGiftUnique) {
      const { ownerName, ownerAddress, ownerId } = gift;
      const ownerPeer = ownerId ? selectPeer(getGlobal(), ownerId) : undefined;
      const {
        model, backdrop, pattern, originalDetails,
      } = giftAttributes || {};

      if (ownerAddress) {
        tableData.push([
          lang('GiftInfoOwner'),
          <span
            className={styles.ownerAddress}
            onClick={() => {
              copyTextToClipboard(ownerAddress);
              showNotification({
                message: { key: 'WalletAddressCopied' },
                icon: 'copy',
              });
            }}
          >
            {ownerAddress}
            <Icon className={styles.copyIcon} name="copy" />
          </span>,
        ]);
      } else if (ownerPeer || ownerName) {
        tableData.push([
          lang('GiftInfoOwner'),
          ownerId ? { chatId: ownerId, withEmojiStatus: true } : ownerName || '',
        ]);
      }

      if (model) {
        tableData.push([
          lang('GiftAttributeModel'),
          <span className={styles.uniqueAttribute}>
            <span
              className={styles.attributeName}
              onClick={handleModelClick}
            >
              {model.name}
            </span>
            <BadgeButton>{formatPercent(model.rarityPercent)}</BadgeButton>
          </span>,
        ]);
      }

      if (backdrop) {
        tableData.push([
          lang('GiftAttributeBackdrop'),
          <span className={styles.uniqueAttribute}>
            <span
              className={styles.attributeName}
              onClick={handleBackdropClick}
            >
              {backdrop.name}
            </span>
            <BadgeButton>{formatPercent(backdrop.rarityPercent)}</BadgeButton>
          </span>,
        ]);
      }

      if (pattern) {
        tableData.push([
          lang('GiftAttributeSymbol'),
          <span className={styles.uniqueAttribute}>
            <span
              className={styles.attributeName}
              onClick={handleSymbolClick}
            >
              {pattern.name}
            </span>
            <BadgeButton>{formatPercent(pattern.rarityPercent)}</BadgeButton>
          </span>,
        ]);
      }

      tableData.push([
        lang('GiftInfoAvailability'),
        lang('GiftInfoIssued', {
          issued: gift.issuedCount,
          total: gift.totalCount,
        }),
      ]);

      if (gift.valueAmount && gift.valueCurrency) {
        tableData.push([
          lang('GiftInfoValue'),
          <span className={styles.uniqueValue}>
            ~
            {' '}
            {formatCurrencyAsString(
              gift.valueAmount,
              gift.valueCurrency,
              lang.code,
            )}
            <BadgeButton onClick={handleOpenValueModal}>
              {lang('GiftInfoValueLinkMore')}
            </BadgeButton>
          </span>,
        ]);
      }

      if (originalDetails) {
        const { recipientId, senderId } = originalDetails;
        const global = getGlobal(); // Peer titles do not need to be reactive

        const openChat = (id: string) => {
          openChatWithInfo({ id });
          closeGiftInfoModal();
        };

        const recipient = selectPeer(global, recipientId)!;
        const sender = senderId ? selectPeer(global, senderId) : undefined;

        const text = renderGiftOriginalInfo({
          originalDetails, recipient, sender, onOpenChat: openChat, lang,
        });

        tableData.push([
          undefined,
          <div className={styles.messageContainer}>
            <div>
              {text}
            </div>
            {Boolean(savedGift?.dropOriginalDetailsStars) && (
              <Button
                round
                className={styles.removeMessageButton}
                size="smaller"
                color="translucent"
                ariaLabel="Delete original details"
                onClick={handleRemoveMessage}
                iconName="delete"
              />
            )}
          </div>,
        ]);
      }
    }

    const tonLink = tonExplorerUrl && isGiftUnique && gift.giftAddress && (
      `${tonExplorerUrl}${gift.giftAddress}`
    );

    const footer = (
      <div className={styles.footer}>
        {(canManage || tonLink || canBuyGift) && (
          <div className={styles.footerDescription}>
            {tonLink && (
              <div>
                {lang('GiftInfoTonText', {
                  link: <SafeLink url={tonLink} shouldSkipModal text={lang('GiftInfoTonLinkText')} />,
                }, { withNodes: true })}
              </div>
            )}
            {canManage && (
              <div>
                {lang(`GiftInfo${isTargetChat ? 'Channel' : ''}${isUnsaved ? 'Hidden' : 'Saved'}`, {
                  link: (
                    <Link isPrimary onClick={handleTriggerVisibility}>
                      {lang(`GiftInfoSaved${isUnsaved ? 'Show' : 'Hide'}`)}
                    </Link>
                  ),
                }, {
                  withNodes: true,
                })}
              </div>
            )}
            {!canBuyGift && isVisibleForMe && (
              <div>
                {lang('GiftInfoSenderHidden')}
              </div>
            )}
            {canBuyGift && giftOwnerTitle && (
              <div>
                {lang('GiftInfoBuyGift', {
                  user: giftOwnerTitle,
                }, { withNodes: true })}
              </div>
            )}
          </div>
        )}
        {renderFooterButton()}
      </div>
    );

    return {
      modalHeader: isGiftUnique ? uniqueGiftModalHeader : undefined,
      header: isGiftUnique ? uniqueGiftHeader : regularHeader,
      tableData,
      footer,
    };
  }, [
    typeGift, savedGift, renderingTargetPeer, giftSticker, lang,
    canManage, hasConvertOption, isSender, oldLang, tonExplorerUrl,
    gift, giftAttributes, renderFooterButton, isTargetChat,
    SettingsMenuButton, isGiftUnique, saleDateInfo,
    canBuyGift, giftOwnerTitle, resellPrice, giftSubtitle,
    releasedByPeer, handleSymbolClick, handleBackdropClick, handleModelClick,
  ]);

  const getRootElement = useLastCallback(() => uniqueGiftHeaderRef.current);
  const getTriggerElement = useLastCallback(() => splitButtonRef.current);
  const getMenuElement = useLastCallback(() => menuRef.current);
  const getLayout = useLastCallback(() => ({ withPortal: true }));

  const uniqueGiftContextMenu = contextMenuAnchor && typeGift && (
    <Menu
      ref={menuRef}
      isOpen={isContextMenuOpen}
      anchor={contextMenuAnchor}
      className="gift-context-menu with-menu-transitions"
      autoClose
      withPortal
      onClose={handleContextMenuClose}
      onCloseAnimationEnd={handleContextMenuHide}
      positionX="right"
      getTriggerElement={getTriggerElement}
      getRootElement={getRootElement}
      getMenuElement={getMenuElement}
      getLayout={getLayout}
    >
      <GiftMenuItems
        peerId={renderingModal!.peerId!}
        gift={typeGift}
        canManage={canManage}
        collectibleEmojiStatuses={collectibleEmojiStatuses}
        currentUserEmojiStatus={currentUserEmojiStatus}
      />
    </Menu>
  );

  return (
    <>
      <TableInfoModal
        isOpen={isOpen}
        modalHeader={modalData?.modalHeader}
        header={modalData?.header}
        hasBackdrop={isGiftUnique}
        tableData={modalData?.tableData}
        footer={modalData?.footer}
        className={styles.modal}
        contentClassName={styles.modalContent}
        onClose={handleClose}
        withBalanceBar={Boolean(canBuyGift)}
        currencyInBalanceBar={confirmPrice?.currency}
        isLowStackPriority
      />
      {uniqueGiftContextMenu}
      {uniqueGift && currentUser && Boolean(confirmPrice) && (
        <ConfirmDialog
          isOpen={isConfirmModalOpen}
          noDefaultTitle
          onClose={closeConfirmModal}
          confirmLabel={lang('ButtonBuyGift', {
            stars: confirmPrice?.currency === TON_CURRENCY_CODE
              ? formatTonAsIcon(lang, confirmPrice.amount, { shouldConvertFromNanos: true })
              : formatStarsAsIcon(lang, confirmPrice.amount, { asFont: true }),
          }, { withNodes: true })}
          confirmHandler={handleConfirmBuyGift}
        >

          {uniqueGift.resaleTonOnly
            && (
              <div className={styles.descriptionConfirm}>
                {lang('ConfirmBuyGiftForTonDescription')}
              </div>
            )}
          <GiftTransferPreview
            peer={recipientPeer || currentUser}
            gift={uniqueGift}
          />
          <div className={styles.titleConfirm}>
            {lang('TitleConfirmPayment')}
          </div>
          {!recipientPeer
            && (
              <p>
                {lang('GiftBuyConfirmDescription', {
                  gift: lang('GiftUnique', { title: uniqueGift.title, number: uniqueGift.number }),
                  stars: confirmPrice?.currency === TON_CURRENCY_CODE
                    ? formatTonAsText(lang, confirmPrice.amount, true)
                    : formatStarsAsText(lang, confirmPrice.amount),
                }, {
                  withNodes: true,
                  withMarkdown: true,
                })}
              </p>
            )}
          {recipientPeer
            && (
              <p>
                {lang('GiftBuyForPeerConfirmDescription', {
                  gift: lang('GiftUnique', { title: uniqueGift.title, number: uniqueGift.number }),
                  stars: confirmPrice?.currency === TON_CURRENCY_CODE
                    ? formatTonAsText(lang, confirmPrice.amount, true)
                    : formatStarsAsText(lang, confirmPrice.amount),
                  peer: getPeerTitle(lang, recipientPeer),
                }, {
                  withNodes: true,
                  withMarkdown: true,
                })}
              </p>
            )}
          {!uniqueGift.resaleTonOnly && (
            <>
              <Checkbox
                className={styles.checkBox}
                label={lang('LabelPayInTON')}
                checked={shouldPayInTon}
                onCheck={setShouldPayInTon}
              />

              <div className={styles.checkBoxDescription}>
                {lang('DescriptionPayInTON')}
              </div>
            </>
          )}
        </ConfirmDialog>
      )}
      {savedGift && (
        <ConfirmDialog
          isOpen={isConvertConfirmOpen}
          onClose={closeConvertConfirm}
          confirmHandler={handleConvertToStars}
          title={lang('GiftInfoConvertTitle')}
        >
          <div>
            {lang('GiftInfoPeerConvertDescription', {
              amount: formatStarsAsText(lang, savedGift.starsToConvert!),
              peer: getPeerTitle(lang, renderingFromPeer!)!,
            }, {
              withNodes: true,
              withMarkdown: true,
            })}
          </div>
          {hasConvertOption && (
            <div>
              {lang('GiftInfoConvertDescriptionPeriod', {
                count: conversionLeft,
              }, {
                withNodes: true,
                withMarkdown: true,
                pluralValue: conversionLeft,
              })}
            </div>
          )}
          <div>{lang('GiftInfoConvertDescription2')}</div>
        </ConfirmDialog>
      )}
    </>
  );
};

export default memo(withGlobal<OwnProps>(
  (global, { modal }): Complete<StateProps> => {
    const typeGift = modal?.gift;
    const isSavedGift = typeGift && 'gift' in typeGift;
    const currentUserId = global.currentUserId;

    const fromId = isSavedGift && typeGift.fromId;
    const fromPeer = fromId ? selectPeer(global, fromId) : undefined;
    const targetPeer = modal?.peerId ? selectPeer(global, modal.peerId) : undefined;
    const chat = targetPeer && isApiPeerChat(targetPeer) ? targetPeer : undefined;
    const hasAdminRights = chat && getHasAdminRight(chat, 'postMessages');
    const currentUser = selectUser(global, currentUserId!);
    const recipientPeer = modal?.recipientId && currentUserId !== modal.recipientId
      ? selectPeer(global, modal.recipientId) : undefined;
    const currentUserEmojiStatus = currentUser?.emojiStatus;
    const collectibleEmojiStatuses = global.collectibleEmojiStatuses?.statuses;

    const gift = isSavedGift ? typeGift.gift : typeGift;
    const releasedByPeerId = gift?.type === 'starGiftUnique' && gift.releasedByPeerId;
    const releasedByPeer = releasedByPeerId ? selectPeer(global, releasedByPeerId) : undefined;

    return {
      fromPeer,
      targetPeer,
      releasedByPeer,
      currentUserId,
      starGiftMaxConvertPeriod: global.appConfig.starGiftMaxConvertPeriod,
      tonExplorerUrl: global.appConfig.tonExplorerUrl,
      hasAdminRights,
      currentUserEmojiStatus,
      collectibleEmojiStatuses,
      currentUser,
      recipientPeer,
    };
  },
)(GiftInfoModal));
