import type { FC } from '../../../lib/teact/teact';
import React, { useMemo, useRef } from '../../../lib/teact/teact';

import type {
  ApiChat,
  ApiMessage, ApiPeer, ApiReplyInfo, MediaContainer,
} from '../../../api/types';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
import type { ChatTranslatedMessages } from '../../../types';
import type { IconName } from '../../../types/icons';

import { CONTENT_NOT_SUPPORTED } from '../../../config';
import {
  getMessageIsSpoiler,
  getMessageMediaHash,
  getMessageRoundVideo,
  getPeerTitle,
  isChatChannel,
  isChatGroup,
  isMessageTranslatable,
  isUserId,
} from '../../../global/helpers';
import { getMediaContentTypeDescription } from '../../../global/helpers/messageSummary';
import buildClassName from '../../../util/buildClassName';
import freezeWhenClosed from '../../../util/hoc/freezeWhenClosed';
import { getPictogramDimensions } from '../helpers/mediaDimensions';
import renderText from '../helpers/renderText';
import { renderTextWithEntities } from '../helpers/renderTextWithEntities';

import { useFastClick } from '../../../hooks/useFastClick';
import { useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import useMedia from '../../../hooks/useMedia';
import useOldLang from '../../../hooks/useOldLang';
import useThumbnail from '../../../hooks/useThumbnail';
import useMessageTranslation from '../../middle/message/hooks/useMessageTranslation';

import RippleEffect from '../../ui/RippleEffect';
import Icon from '../icons/Icon';
import MediaSpoiler from '../MediaSpoiler';
import MessageSummary from '../MessageSummary';
import PeerColorWrapper from '../PeerColorWrapper';

import './EmbeddedMessage.scss';

type OwnProps = {
  className?: string;
  replyInfo?: ApiReplyInfo;
  message?: ApiMessage;
  sender?: ApiPeer;
  senderChat?: ApiChat;
  forwardSender?: ApiPeer;
  title?: string;
  customText?: string;
  noUserColors?: boolean;
  isProtected?: boolean;
  isInComposer?: boolean;
  chatTranslations?: ChatTranslatedMessages;
  requestedChatTranslationLanguage?: string;
  isOpen?: boolean;
  observeIntersectionForLoading?: ObserveFn;
  observeIntersectionForPlaying?: ObserveFn;
  onClick: ((e: React.MouseEvent) => void);
};

const NBSP = '\u00A0';
const EMOJI_SIZE = 17;

const EmbeddedMessage: FC<OwnProps> = ({
  className,
  message,
  replyInfo,
  sender,
  senderChat,
  forwardSender,
  title,
  customText,
  isProtected,
  isInComposer,
  noUserColors,
  chatTranslations,
  requestedChatTranslationLanguage,
  observeIntersectionForLoading,
  observeIntersectionForPlaying,
  onClick,
}) => {
  // eslint-disable-next-line no-null/no-null
  const ref = useRef<HTMLDivElement>(null);
  const isIntersecting = useIsIntersecting(ref, observeIntersectionForLoading);

  const containedMedia: MediaContainer | undefined = useMemo(() => {
    const media = (replyInfo?.type === 'message' && replyInfo.replyMedia) || message?.content;
    if (!media) {
      return undefined;
    }

    return {
      content: media,
    };
  }, [message, replyInfo]);

  const gif = containedMedia?.content?.video?.isGif ? containedMedia.content.video : undefined;
  const isVideoThumbnail = Boolean(gif && !gif.previewPhotoSizes?.length);

  const mediaHash = containedMedia && getMessageMediaHash(containedMedia, isVideoThumbnail ? 'full' : 'pictogram');
  const mediaBlobUrl = useMedia(mediaHash, !isIntersecting);
  const mediaThumbnail = useThumbnail(containedMedia);

  const isRoundVideo = Boolean(containedMedia && getMessageRoundVideo(containedMedia));
  const isSpoiler = Boolean(containedMedia && getMessageIsSpoiler(containedMedia));
  const isQuote = Boolean(replyInfo?.type === 'message' && replyInfo.isQuote);
  const replyForwardInfo = replyInfo?.type === 'message' ? replyInfo.replyFrom : undefined;

  const shouldTranslate = message && isMessageTranslatable(message);
  const { translatedText } = useMessageTranslation(
    chatTranslations, message?.chatId, shouldTranslate ? message?.id : undefined, requestedChatTranslationLanguage,
  );

  const lang = useOldLang();

  const senderTitle = sender ? getPeerTitle(lang, sender)
    : (replyForwardInfo?.hiddenUserName || message?.forwardInfo?.hiddenUserName);
  const senderChatTitle = senderChat ? getPeerTitle(lang, senderChat) : undefined;
  const forwardSenderTitle = forwardSender ? getPeerTitle(lang, forwardSender)
    : message?.forwardInfo?.hiddenUserName;
  const areSendersSame = sender && sender.id === forwardSender?.id;

  const { handleClick, handleMouseDown } = useFastClick(onClick);

  function renderTextContent() {
    if (replyInfo?.type === 'message' && replyInfo.quoteText) {
      return renderTextWithEntities({
        text: replyInfo.quoteText.text,
        entities: replyInfo.quoteText.entities,
        asPreview: true,
        emojiSize: EMOJI_SIZE,
      });
    }

    if (!message) {
      return customText || renderMediaContentType(containedMedia) || NBSP;
    }

    return (
      <MessageSummary
        message={message}
        noEmoji={Boolean(mediaThumbnail)}
        translatedText={translatedText}
        observeIntersectionForLoading={observeIntersectionForLoading}
        observeIntersectionForPlaying={observeIntersectionForPlaying}
        emojiSize={EMOJI_SIZE}
      />
    );
  }

  function renderMediaContentType(media?: MediaContainer) {
    if (!media || media.content.text) return NBSP;
    const description = getMediaContentTypeDescription(lang, media.content, {});
    if (!description || description === CONTENT_NOT_SUPPORTED) return NBSP;
    return (
      <span>
        {renderText(description)}
      </span>
    );
  }

  function checkShouldRenderSenderTitle() {
    if (!senderChat) return true;
    if (isUserId(senderChat?.id)) return true;
    if (senderChat.id === sender?.id) return false;
    return true;
  }
  function renderSender() {
    if (title) {
      return renderText(title);
    }

    if (!senderTitle) {
      return NBSP;
    }

    let icon: IconName | undefined;
    if (senderChat) {
      if (isChatChannel(senderChat)) {
        icon = 'channel-filled';
      }

      if (isChatGroup(senderChat)) {
        icon = 'group-filled';
      }
    }

    const isReplyToQuote = isInComposer && Boolean(replyInfo && 'quoteText' in replyInfo && replyInfo?.quoteText);

    return (
      <span className="embedded-sender-wrapper">
        {checkShouldRenderSenderTitle() && (
          <span className="embedded-sender">
            {renderText(isReplyToQuote ? lang('ReplyToQuote', senderTitle) : senderTitle)}
          </span>
        )}
        {icon && <Icon name={icon} className="embedded-chat-icon" />}
        {icon && senderChatTitle && (
          <span className="embedded-sender-chat">
            {renderText(senderChatTitle)}
          </span>
        )}
      </span>
    );
  }

  function renderForwardSender() {
    return forwardSenderTitle && !areSendersSame && (
      <span className="embedded-forward-sender-wrapper">
        <Icon name={forwardSender ? 'share-filled' : 'forward'} className="embedded-origin-icon" />
        <span className="forward-sender-title">
          {renderText(forwardSenderTitle)}
        </span>
      </span>
    );
  }

  return (
    <PeerColorWrapper
      peer={sender}
      emojiIconClassName=' className="EmbeddedMessage--background-icons"'
      ref={ref}
      shouldReset
      noUserColors={noUserColors}
      className={buildClassName(
        'EmbeddedMessage',
        className,
        isQuote && 'is-quote',
        mediaThumbnail && 'with-thumb',
      )}
      dir={lang.isRtl ? 'rtl' : undefined}
      onClick={handleClick}
      onMouseDown={handleMouseDown}
    >
      <div className="hover-effect" />
      <RippleEffect />
      {mediaThumbnail && renderPictogram(
        mediaThumbnail, mediaBlobUrl, isVideoThumbnail, isRoundVideo, isProtected, isSpoiler,
      )}
      <div className="message-text">
        <p className={buildClassName('embedded-text-wrapper', isQuote && 'multiline')}>
          {renderTextContent()}
        </p>
        <div className="message-title">
          {renderSender()}
          {renderForwardSender()}
        </div>
      </div>
    </PeerColorWrapper>
  );
};

function renderPictogram(
  thumbDataUri: string,
  blobUrl?: string,
  isFullVideo?: boolean,
  isRoundVideo?: boolean,
  isProtected?: boolean,
  isSpoiler?: boolean,
) {
  const { width, height } = getPictogramDimensions();

  const srcUrl = blobUrl || thumbDataUri;
  const shouldRenderVideo = isFullVideo && blobUrl;

  return (
    <div className={buildClassName('embedded-thumb', isRoundVideo && 'round')}>
      {!isSpoiler && !shouldRenderVideo && (
        <img
          src={srcUrl}
          width={width}
          height={height}
          alt=""
          className="pictogram"
          draggable={false}
        />
      )}
      {!isSpoiler && shouldRenderVideo && (
        <video
          src={blobUrl}
          width={width}
          height={height}
          playsInline
          disablePictureInPicture
          className="pictogram"
        />
      )}
      <MediaSpoiler
        thumbDataUri={shouldRenderVideo ? thumbDataUri : srcUrl}
        isVisible={Boolean(isSpoiler)}
        width={width}
        height={height}
      />
      {isProtected && <span className="protector" />}
    </div>
  );
}

export const ClosableEmbeddedMessage = freezeWhenClosed(EmbeddedMessage);

export default EmbeddedMessage;
