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

import type {
  ApiPeer,
  ApiStarGiftAttribute,
  ApiStarGiftAttributeBackdrop,
  ApiStarGiftAttributeModel,
  ApiStarGiftAttributePattern,
} from '../../../../api/types';
import type { TabState } from '../../../../global/types';
import { ApiMediaFormat } from '../../../../api/types';

import { getStickerMediaHash } from '../../../../global/helpers';
import { getPeerTitle } from '../../../../global/helpers/peers';
import { selectPeer } from '../../../../global/selectors';
import { fetch } from '../../../../util/mediaLoader';

import useInterval from '../../../../hooks/schedulers/useInterval';
import useCurrentOrPrev from '../../../../hooks/useCurrentOrPrev';
import useLang from '../../../../hooks/useLang';
import useLastCallback from '../../../../hooks/useLastCallback';

import AnimatedCounter from '../../../common/AnimatedCounter';
import Icon from '../../../common/icons/Icon';
import Button from '../../../ui/Button';
import Checkbox from '../../../ui/Checkbox';
import Link from '../../../ui/Link';
import TextTimer from '../../../ui/TextTimer';
import TableAboutModal, { type TableAboutData } from '../../common/TableAboutModal';
import UniqueGiftHeader from '../UniqueGiftHeader';

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

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

type StateProps = {
  recipient?: ApiPeer;
};

type Attributes = {
  model: ApiStarGiftAttributeModel;
  pattern: ApiStarGiftAttributePattern;
  backdrop: ApiStarGiftAttributeBackdrop;
};

const PREVIEW_UPDATE_INTERVAL = 3000;

const GiftUpgradeModal = ({ modal, recipient }: OwnProps & StateProps) => {
  const {
    closeGiftUpgradeModal,
    closeGiftInfoModal,
    upgradeGift,
    upgradePrepaidGift,
    openStarGiftPriceDecreaseInfoModal,
    shiftGiftUpgradeNextPrice,
  } = getActions();
  const isOpen = Boolean(modal);

  const renderingModal = useCurrentOrPrev(modal);
  const renderingRecipient = useCurrentOrPrev(recipient);
  const [shouldKeepOriginalDetails, setShouldKeepOriginalDetails] = useState(false);

  const isPrepaid = Boolean(renderingModal?.gift?.prepaidUpgradeHash);

  const [previewAttributes, setPreviewAttributes] = useState<Attributes | undefined>();

  const lang = useLang();

  const handleClose = useLastCallback(() => closeGiftUpgradeModal());

  const handleTimerEnd = useLastCallback(() => {
    shiftGiftUpgradeNextPrice();
  });

  const nextPrice = renderingModal?.nextPrices?.[0];
  const nextPriceDate = nextPrice?.date;
  const upgradeStars = renderingModal?.currentUpgradeStars;

  const handleUpgrade = useLastCallback(() => {
    const gift = renderingModal?.gift;

    if (!gift) return;

    if (isPrepaid && gift.prepaidUpgradeHash && renderingRecipient) {
      if (!upgradeStars) return;

      upgradePrepaidGift({
        peerId: renderingRecipient.id,
        hash: gift.prepaidUpgradeHash,
        stars: upgradeStars,
      });
      handleClose();
      closeGiftInfoModal();
      return;
    }

    if (!gift?.inputGift) return;

    upgradeGift({
      gift: gift.inputGift,
      shouldKeepOriginalDetails,
      upgradeStars: !gift.alreadyPaidUpgradeStars ? upgradeStars : undefined,
    });
    handleClose();
  });

  const updatePreviewAttributes = useLastCallback(() => {
    if (!renderingModal?.sampleAttributes) return;
    setPreviewAttributes(getRandomAttributes(renderingModal.sampleAttributes, previewAttributes));
  });

  const handleOpenPriceInfo = useLastCallback(() => {
    if (!renderingModal?.prices) return;

    openStarGiftPriceDecreaseInfoModal({
      prices: renderingModal.prices,
      currentPrice: upgradeStars || 0,
      minPrice: renderingModal.minPrice || 0,
      maxPrice: renderingModal.maxPrice || 0,
    });
  });

  useInterval(updatePreviewAttributes, isOpen ? PREVIEW_UPDATE_INTERVAL : undefined, true);

  useEffect(() => {
    if (isOpen && renderingModal?.sampleAttributes) {
      updatePreviewAttributes();
    }
  }, [isOpen, renderingModal?.sampleAttributes]);

  // Preload stickers and patterns
  useEffect(() => {
    const attributes = renderingModal?.sampleAttributes;
    if (!attributes) return;
    const patternStickers = attributes.filter((attr): attr is ApiStarGiftAttributeModel => attr.type === 'pattern')
      .map((attr) => attr.sticker);
    const modelStickers = attributes.filter((attr): attr is ApiStarGiftAttributeModel => attr.type === 'model')
      .map((attr) => attr.sticker);

    const mediaHashes = [...patternStickers, ...modelStickers].map((sticker) => getStickerMediaHash(sticker, 'full'));
    mediaHashes.forEach((hash) => {
      fetch(hash, ApiMediaFormat.BlobUrl);
    });
  }, [renderingModal?.sampleAttributes]);

  const formattedPriceElement = useMemo(() => (upgradeStars ? (
    <span>
      <Icon name="star" className="star-amount-icon" />
      <AnimatedCounter text={lang.number(upgradeStars)} />
    </span>
  ) : undefined), [lang, upgradeStars]);

  const modalData = useMemo(() => {
    if (!previewAttributes || !isOpen) {
      return undefined;
    }

    const gift = renderingModal?.gift;

    const userName = renderingRecipient ? getPeerTitle(lang, renderingRecipient) : lang('ActionFallbackUser');

    const listItemData = (renderingRecipient ? [
      ['diamond', lang('GiftUpgradeUniqueTitle'), lang('GiftPeerUpgradeUniqueDescription', { user: userName })],
      ['trade', lang('GiftUpgradeTransferableTitle'),
        lang('GiftPeerUpgradeTransferableDescription', { user: userName })],
      ['auction', lang('GiftUpgradeTradeableTitle'), lang('GiftPeerUpgradeTradeableDescription', { user: userName })],
    ] : [
      ['diamond', lang('GiftUpgradeUniqueTitle'), lang('GiftUpgradeUniqueDescription')],
      ['trade', lang('GiftUpgradeTransferableTitle'), lang('GiftUpgradeTransferableDescription')],
      ['auction', lang('GiftUpgradeTradeableTitle'), lang('GiftUpgradeTradeableDescription')],
    ]) satisfies TableAboutData;

    const subtitle = renderingRecipient
      ? lang('GiftPeerUpgradeText', { peer: getPeerTitle(lang, renderingRecipient) })
      : lang('GiftUpgradeTextOwn');

    const hasPriceDecreaseInfo = Boolean(nextPriceDate)
      && Boolean(renderingModal?.prices?.length)
      && !gift?.alreadyPaidUpgradeStars;

    const header = (
      <UniqueGiftHeader
        modelAttribute={previewAttributes.model}
        backdropAttribute={previewAttributes.backdrop}
        patternAttribute={previewAttributes.pattern}
        title={lang('GiftUpgradeTitle')}
        subtitle={subtitle}
      />
    );

    const footer = (
      <div className={styles.footer}>
        {!gift && (
          <Button className={styles.footerButton} onClick={handleClose}>
            {lang('OK')}
          </Button>
        )}
        {gift && (
          <>
            {!isPrepaid && (
              <Checkbox
                label={lang('GiftUpgradeKeepDetails')}
                onCheck={setShouldKeepOriginalDetails}
                checked={shouldKeepOriginalDetails}
              />
            )}
            <Button className={styles.footerButton} isShiny onClick={handleUpgrade}>
              <div className={styles.buttonContent}>
                <div>
                  {gift.alreadyPaidUpgradeStars
                    ? lang('GeneralConfirm')
                    : isPrepaid
                      ? lang('GiftPayForUpgradeButton', { amount: formattedPriceElement }, { withNodes: true })
                      : lang('GiftUpgradeButton', { amount: formattedPriceElement }, { withNodes: true })}
                </div>
                {hasPriceDecreaseInfo && (
                  <div className={styles.priceDecreaseTimer}>
                    {lang('StarGiftPriceDecreaseTimer', {
                      timer: <TextTimer endsAt={nextPriceDate} onEnd={handleTimerEnd} />,
                    }, { withNodes: true })}
                  </div>
                )}
              </div>
            </Button>
            {hasPriceDecreaseInfo && (
              <Link
                className={styles.link}
                isPrimary
                onClick={handleOpenPriceInfo}
              >
                {lang('StarGiftPriceDecreaseInfoLink')}
              </Link>
            )}
          </>
        )}
      </div>
    );

    return {
      listItemData,
      header,
      footer,
    };
  }, [previewAttributes, isOpen, lang,
    renderingRecipient, renderingModal?.gift,
    shouldKeepOriginalDetails, isPrepaid,
    renderingModal?.prices?.length,
    nextPriceDate, formattedPriceElement]);

  return (
    <TableAboutModal
      isOpen={isOpen}
      header={modalData?.header}
      footer={modalData?.footer}
      listItemData={modalData?.listItemData}
      hasBackdrop
      onClose={handleClose}
    />
  );
};

export default memo(withGlobal<OwnProps>(
  (global, { modal }): Complete<StateProps> => {
    const recipientId = modal?.recipientId;
    const recipient = recipientId ? selectPeer(global, recipientId) : undefined;

    return {
      recipient,
    };
  },
)(GiftUpgradeModal));

function getRandomAttributes(list: ApiStarGiftAttribute[], previousSelection?: Attributes): Attributes {
  const models = list.filter((attr): attr is ApiStarGiftAttributeModel => (
    attr.type === 'model' && attr.name !== previousSelection?.model.name
  ));
  const patterns = list.filter((attr): attr is ApiStarGiftAttributePattern => (
    attr.type === 'pattern' && attr.name !== previousSelection?.pattern.name
  ));
  const backdrops = list.filter((attr): attr is ApiStarGiftAttributeBackdrop => (
    attr.type === 'backdrop' && attr.name !== previousSelection?.backdrop.name
  ));

  const randomModel = models[Math.floor(Math.random() * models.length)];
  const randomPattern = patterns[Math.floor(Math.random() * patterns.length)];
  const randomBackdrop = backdrops[Math.floor(Math.random() * backdrops.length)];

  return {
    model: randomModel,
    pattern: randomPattern,
    backdrop: randomBackdrop,
  };
}
