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

import type {
  ApiPremiumGiftCodeOption,
  ApiStarGiftRegular,
  ApiStarsAmount,
  ApiUser,
} from '../../../api/types';
import type { TabState } from '../../../global/types';
import type { StarGiftCategory } from '../../../types';

import { getUserFullName } from '../../../global/helpers';
import { selectUser } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';

import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';

import Avatar from '../../common/Avatar';
import SafeLink from '../../common/SafeLink';
import Button from '../../ui/Button';
import Modal from '../../ui/Modal';
import Transition from '../../ui/Transition';
import BalanceBlock from '../stars/BalanceBlock';
import GiftSendingOptions from './GiftComposer';
import GiftItemPremium from './GiftItemPremium';
import GiftItemStar from './GiftItemStar';
import StarGiftCategoryList from './StarGiftCategoryList';

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

import StarsBackground from '../../../assets/stars-bg.png';

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

export type GiftOption = ApiPremiumGiftCodeOption | ApiStarGiftRegular;

type StateProps = {
  boostPerSentGift?: number;
  starGiftsById?: Record<string, ApiStarGiftRegular>;
  starGiftCategoriesByName: Record<StarGiftCategory, string[]>;
  starBalance?: ApiStarsAmount;
  user?: ApiUser;
  isSelf?: boolean;
};

const AVATAR_SIZE = 100;
const INTERSECTION_THROTTLE = 200;

const PremiumGiftModal: FC<OwnProps & StateProps> = ({
  modal,
  starGiftsById,
  starGiftCategoriesByName,
  starBalance,
  user,
  isSelf,
}) => {
  const {
    closeGiftModal, requestConfetti,
  } = getActions();
  // eslint-disable-next-line no-null/no-null
  const dialogRef = useRef<HTMLDivElement>(null);
  // eslint-disable-next-line no-null/no-null
  const transitionRef = useRef<HTMLDivElement>(null);
  // eslint-disable-next-line no-null/no-null
  const giftHeaderRef = useRef<HTMLHeadingElement>(null);

  // eslint-disable-next-line no-null/no-null
  const scrollerRef = useRef<HTMLDivElement>(null);

  const isOpen = Boolean(modal);
  const renderingModal = useCurrentOrPrev(modal);

  const [selectedGift, setSelectedGift] = useState<GiftOption | undefined>();
  const [isHeaderHidden, setIsHeaderHidden] = useState(true);
  const [isHeaderForStarGifts, setIsHeaderForStarGifts] = useState(false);

  const [selectedCategory, setSelectedCategory] = useState<StarGiftCategory>('all');

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

  const filteredGifts = useMemo(() => {
    return renderingModal?.gifts?.sort((prevGift, gift) => prevGift.months - gift.months)
      .filter((gift) => gift.users === 1);
  }, [renderingModal]);

  const baseGift = useMemo(() => {
    return filteredGifts?.reduce((prev, gift) => (prev.amount < gift.amount ? prev : gift));
  }, [filteredGifts]);

  const {
    observe: observeIntersection,
  } = useIntersectionObserver({ rootRef: scrollerRef, throttleMs: INTERSECTION_THROTTLE, isDisabled: !isOpen });

  const showConfetti = useLastCallback(() => {
    const dialog = dialogRef.current;
    if (!dialog) return;
    if (isOpen) {
      const {
        top, left, width, height,
      } = dialog.querySelector('.modal-content')!.getBoundingClientRect();
      requestConfetti({
        top,
        left,
        width,
        height,
        withStars: true,
      });
    }
  });

  useEffect(() => {
    if (renderingModal?.isCompleted) {
      showConfetti();
    }
  }, [renderingModal]);

  useEffect(() => {
    if (!isOpen) {
      setIsHeaderHidden(true);
      setSelectedGift(undefined);
    }
  }, [isOpen]);

  const handleScroll = useLastCallback((e: React.UIEvent<HTMLDivElement>) => {
    if (selectedGift) return;

    const { scrollTop } = e.currentTarget;

    setIsHeaderHidden(scrollTop <= 150);

    if (transitionRef.current && giftHeaderRef.current) {
      const { top: headerTop } = giftHeaderRef.current.getBoundingClientRect();
      const { top: transitionTop } = transitionRef.current.getBoundingClientRect();
      setIsHeaderForStarGifts(headerTop - transitionTop <= 0);
    }
  });

  const giftPremiumDescription = lang('GiftPremiumDescription', {
    user: getUserFullName(user)!,
    link: (
      <SafeLink
        text={lang('GiftPremiumDescriptionLinkCaption')}
        url={lang('GiftPremiumDescriptionLink')}
      />
    ),
  }, { withNodes: true });

  const starGiftDescription = isSelf
    ? lang('StarGiftDescriptionSelf', undefined, {
      withNodes: true,
      renderTextFilters: ['br'],
    })
    : lang('StarGiftDescription', {
      user: getUserFullName(user)!,
    }, { withNodes: true, withMarkdown: true });

  function renderGiftPremiumHeader() {
    return (
      <h2 className={buildClassName(styles.headerText, styles.center)}>
        {lang('GiftPremiumHeader')}
      </h2>
    );
  }

  function renderGiftPremiumDescription() {
    return (
      <p className={buildClassName(styles.description, styles.center)}>
        {giftPremiumDescription}
      </p>
    );
  }

  function renderStarGiftsHeader() {
    return (
      <h2 ref={giftHeaderRef} className={buildClassName(styles.headerText, styles.center)}>
        {lang(isSelf ? 'StarsGiftHeaderSelf' : 'StarsGiftHeader')}
      </h2>
    );
  }

  function renderStarGiftsDescription() {
    return (
      <p className={buildClassName(styles.description, styles.starGiftsDescription, styles.center)}>
        {starGiftDescription}
      </p>
    );
  }

  const handleGiftClick = useLastCallback((gift: GiftOption) => {
    setSelectedGift(gift);
    setIsHeaderForStarGifts('id' in gift);
    setIsHeaderHidden(false);
  });

  function renderStarGifts() {
    return (
      <div className={styles.starGiftsContainer}>
        {starGiftsById && starGiftCategoriesByName[selectedCategory].map((giftId) => {
          const gift = starGiftsById[giftId];
          return (
            <GiftItemStar
              gift={gift}
              observeIntersection={observeIntersection}
              onClick={handleGiftClick}
            />
          );
        })}
      </div>
    );
  }

  function renderPremiumGifts() {
    return (
      <div className={styles.premiumGiftsGallery}>
        {filteredGifts?.map((gift) => {
          return (
            <GiftItemPremium
              option={gift}
              baseMonthAmount={baseGift ? Math.floor(baseGift.amount / baseGift.months) : undefined}
              onClick={handleGiftClick}
            />
          );
        })}
      </div>
    );
  }

  const onCategoryChanged = useLastCallback((category: StarGiftCategory) => {
    setSelectedCategory(category);
  });

  const handleCloseButtonClick = useLastCallback(() => {
    if (selectedGift) {
      setSelectedGift(undefined);
      return;
    }
    closeGiftModal();
  });

  function renderMainScreen() {
    return (
      <div ref={scrollerRef} className={buildClassName(styles.main, 'custom-scroll')} onScroll={handleScroll}>
        <div className={styles.avatars}>
          <Avatar
            size={AVATAR_SIZE}
            peer={user}
          />
          <img className={styles.logoBackground} src={StarsBackground} alt="" draggable={false} />
        </div>
        {!isSelf && renderGiftPremiumHeader()}
        {!isSelf && renderGiftPremiumDescription()}
        {!isSelf && renderPremiumGifts()}

        {renderStarGiftsHeader()}
        {renderStarGiftsDescription()}
        <StarGiftCategoryList onCategoryChanged={onCategoryChanged} />
        <Transition
          name="zoomFade"
          activeKey={getCategoryKey(selectedCategory)}
          className={styles.starGiftsTransition}
        >
          {renderStarGifts()}
        </Transition>
      </div>
    );
  }

  const isBackButton = Boolean(selectedGift);

  const buttonClassName = buildClassName(
    'animated-close-icon',
    isBackButton && 'state-back',
  );

  return (
    <Modal
      dialogRef={dialogRef}
      onClose={closeGiftModal}
      isOpen={isOpen}
      isSlim
      contentClassName={styles.content}
      className={buildClassName(styles.modalDialog, styles.root)}
    >
      <Button
        className={styles.closeButton}
        round
        color="translucent"
        size="smaller"
        onClick={handleCloseButtonClick}
        ariaLabel={isBackButton ? oldLang('Common.Back') : oldLang('Common.Close')}
      >
        <div className={buttonClassName} />
      </Button>
      <BalanceBlock className={styles.balance} balance={starBalance} />
      <div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>
        <Transition
          name="slideVerticalFade"
          activeKey={Number(isHeaderForStarGifts)}
          slideClassName={styles.headerSlide}
        >
          <h2 className={styles.commonHeaderText}>
            {lang(isHeaderForStarGifts ? (isSelf ? 'StarsGiftHeaderSelf' : 'StarsGiftHeader') : 'GiftPremiumHeader')}
          </h2>
        </Transition>
      </div>
      <Transition
        ref={transitionRef}
        className={styles.transition}
        name="pushSlide"
        activeKey={selectedGift ? 1 : 0}
      >
        {!selectedGift && renderMainScreen()}
        {selectedGift && renderingModal?.forUserId && (
          <GiftSendingOptions gift={selectedGift} userId={renderingModal.forUserId} />
        )}
      </Transition>
    </Modal>
  );
};

export default memo(withGlobal<OwnProps>((global, { modal }): StateProps => {
  const {
    starGiftsById,
    starGiftCategoriesByName,
    stars,
    currentUserId,
  } = global;

  const user = modal?.forUserId ? selectUser(global, modal.forUserId) : undefined;
  const isSelf = Boolean(currentUserId && modal?.forUserId === currentUserId);

  return {
    boostPerSentGift: global.appConfig?.boostsPerSentGift,
    starGiftsById,
    starGiftCategoriesByName,
    starBalance: stars?.balance,
    user,
    isSelf,
  };
})(PremiumGiftModal));

function getCategoryKey(category: StarGiftCategory) {
  if (category === 'all') return -2;
  if (category === 'stock') return -1;
  if (category === 'limited') return 0;
  return category;
}
