/* eslint-disable @typescript-eslint/no-unsafe-member-access,
                  @typescript-eslint/no-unsafe-call,
                  @typescript-eslint/no-explicit-any,
                  @typescript-eslint/no-unsafe-assignment */

import type { CSSProperties } from 'react';
import { useState, useRef, useCallback } from 'react';

import { FormattedDate, FormattedMessage } from 'react-intl';

import classNames from 'classnames';
import { Link } from 'react-router-dom';

import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import { AnimatedNumber } from 'mastodon/components/animated_number';
import { ContentWarning } from 'mastodon/components/content_warning';
import EditedTimestamp from 'mastodon/components/edited_timestamp';
import type { StatusLike } from 'mastodon/components/hashtag_bar';
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
import { Icon } from 'mastodon/components/icon';
import { IconLogo } from 'mastodon/components/logo';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';

import { Avatar } from '../../../components/avatar';
import { DisplayName } from '../../../components/display_name';
import MediaGallery from '../../../components/media_gallery';
import StatusContent from '../../../components/status_content';
import Audio from '../../audio';
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
import Video from '../../video';

import Card from './card';

interface VideoModalOptions {
  startTime: number;
  autoPlay?: boolean;
  defaultVolume: number;
  componentIndex: number;
}

export const DetailedStatus: React.FC<{
  status: any;
  onOpenMedia?: (status: any, index: number, lang: string) => void;
  onOpenVideo?: (status: any, lang: string, options: VideoModalOptions) => void;
  onTranslate?: (status: any) => void;
  measureHeight?: boolean;
  onHeightChange?: () => void;
  domain: string;
  showMedia?: boolean;
  withLogo?: boolean;
  pictureInPicture: any;
  onToggleHidden?: (status: any) => void;
  onToggleMediaVisibility?: () => void;
}> = ({
  status,
  onOpenMedia,
  onOpenVideo,
  onTranslate,
  measureHeight,
  onHeightChange,
  domain,
  showMedia,
  withLogo,
  pictureInPicture,
  onToggleMediaVisibility,
  onToggleHidden,
}) => {
  const properStatus = status?.get('reblog') ?? status;
  const [height, setHeight] = useState(0);
  const nodeRef = useRef<HTMLDivElement>();

  const handleOpenVideo = useCallback(
    (options: VideoModalOptions) => {
      const lang = (status.getIn(['translation', 'language']) ||
        status.get('language')) as string;
      if (onOpenVideo)
        onOpenVideo(status.getIn(['media_attachments', 0]), lang, options);
    },
    [onOpenVideo, status],
  );

  const handleExpandedToggle = useCallback(() => {
    if (onToggleHidden) onToggleHidden(status);
  }, [onToggleHidden, status]);

  const _measureHeight = useCallback(
    (heightJustChanged?: boolean) => {
      if (measureHeight && nodeRef.current) {
        scheduleIdleTask(() => {
          if (nodeRef.current)
            setHeight(Math.ceil(nodeRef.current.scrollHeight) + 1);
        });

        if (onHeightChange && heightJustChanged) {
          onHeightChange();
        }
      }
    },
    [onHeightChange, measureHeight, setHeight],
  );

  const handleRef = useCallback(
    (c: HTMLDivElement) => {
      nodeRef.current = c;
      _measureHeight();
    },
    [_measureHeight],
  );

  const handleTranslate = useCallback(() => {
    if (onTranslate) onTranslate(status);
  }, [onTranslate, status]);

  if (!properStatus) {
    return null;
  }

  let media;
  let applicationLink;
  let reblogLink;
  let attachmentAspectRatio;

  if (properStatus.get('media_attachments').getIn([0, 'type']) === 'video') {
    attachmentAspectRatio = `${properStatus.get('media_attachments').getIn([0, 'meta', 'original', 'width'])} / ${properStatus.get('media_attachments').getIn([0, 'meta', 'original', 'height'])}`;
  } else if (
    properStatus.get('media_attachments').getIn([0, 'type']) === 'audio'
  ) {
    attachmentAspectRatio = '16 / 9';
  } else {
    attachmentAspectRatio =
      properStatus.get('media_attachments').size === 1 &&
      properStatus
        .get('media_attachments')
        .getIn([0, 'meta', 'small', 'aspect'])
        ? properStatus
            .get('media_attachments')
            .getIn([0, 'meta', 'small', 'aspect'])
        : '3 / 2';
  }

  const outerStyle = { boxSizing: 'border-box' } as CSSProperties;

  if (measureHeight) {
    outerStyle.height = height;
  }

  const language =
    status.getIn(['translation', 'language']) || status.get('language');

  if (pictureInPicture.get('inUse')) {
    media = <PictureInPicturePlaceholder aspectRatio={attachmentAspectRatio} />;
  } else if (status.get('media_attachments').size > 0) {
    if (
      ['image', 'gifv', 'unknown'].includes(
        status.getIn(['media_attachments', 0, 'type']) as string,
      ) ||
      status.get('media_attachments').size > 1
    ) {
      media = (
        <MediaGallery
          standalone
          sensitive={status.get('sensitive')}
          media={status.get('media_attachments')}
          lang={language}
          height={300}
          onOpenMedia={onOpenMedia}
          visible={showMedia}
          onToggleVisibility={onToggleMediaVisibility}
        />
      );
    } else if (status.getIn(['media_attachments', 0, 'type']) === 'audio') {
      const attachment = status.getIn(['media_attachments', 0]);
      const description =
        attachment.getIn(['translation', 'description']) ||
        attachment.get('description');

      media = (
        <Audio
          src={attachment.get('url')}
          alt={description}
          lang={language}
          duration={attachment.getIn(['meta', 'original', 'duration'], 0)}
          poster={
            attachment.get('preview_url') ||
            status.getIn(['account', 'avatar_static'])
          }
          backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
          foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
          accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
          sensitive={status.get('sensitive')}
          visible={showMedia}
          blurhash={attachment.get('blurhash')}
          height={150}
          onToggleVisibility={onToggleMediaVisibility}
        />
      );
    } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
      const attachment = status.getIn(['media_attachments', 0]);
      const description =
        attachment.getIn(['translation', 'description']) ||
        attachment.get('description');

      media = (
        <Video
          preview={attachment.get('preview_url')}
          frameRate={attachment.getIn(['meta', 'original', 'frame_rate'])}
          aspectRatio={`${attachment.getIn(['meta', 'original', 'width'])} / ${attachment.getIn(['meta', 'original', 'height'])}`}
          blurhash={attachment.get('blurhash')}
          src={attachment.get('url')}
          alt={description}
          lang={language}
          width={300}
          height={150}
          onOpenVideo={handleOpenVideo}
          sensitive={status.get('sensitive')}
          visible={showMedia}
          onToggleVisibility={onToggleMediaVisibility}
        />
      );
    }
  } else if (status.get('card')) {
    media = (
      <Card
        sensitive={status.get('sensitive')}
        onOpenMedia={onOpenMedia}
        card={status.get('card')}
      />
    );
  }

  if (status.get('application')) {
    applicationLink = (
      <>
        ·
        <a
          className='detailed-status__application'
          href={status.getIn(['application', 'website'])}
          target='_blank'
          rel='noopener noreferrer'
        >
          {status.getIn(['application', 'name'])}
        </a>
      </>
    );
  }

  const visibilityLink = (
    <>
      ·<VisibilityIcon visibility={status.get('visibility')} />
    </>
  );

  if (['private', 'direct'].includes(status.get('visibility') as string)) {
    reblogLink = '';
  } else {
    reblogLink = (
      <Link
        to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/reblogs`}
        className='detailed-status__link'
      >
        <span className='detailed-status__reblogs'>
          <AnimatedNumber value={status.get('reblogs_count')} />
        </span>
        <FormattedMessage
          id='status.reblogs'
          defaultMessage='{count, plural, one {boost} other {boosts}}'
          values={{ count: status.get('reblogs_count') }}
        />
      </Link>
    );
  }

  const favouriteLink = (
    <Link
      to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}/favourites`}
      className='detailed-status__link'
    >
      <span className='detailed-status__favorites'>
        <AnimatedNumber value={status.get('favourites_count')} />
      </span>
      <FormattedMessage
        id='status.favourites'
        defaultMessage='{count, plural, one {favorite} other {favorites}}'
        values={{ count: status.get('favourites_count') }}
      />
    </Link>
  );

  const { statusContentProps, hashtagBar } = getHashtagBarForStatus(
    status as StatusLike,
  );
  const expanded =
    !status.get('hidden') || status.get('spoiler_text').length === 0;

  return (
    <div style={outerStyle}>
      <div ref={handleRef} className={classNames('detailed-status')}>
        {status.get('visibility') === 'direct' && (
          <div className='status__prepend'>
            <div className='status__prepend-icon-wrapper'>
              <Icon
                id='at'
                icon={AlternateEmailIcon}
                className='status__prepend-icon'
              />
            </div>
            <FormattedMessage
              id='status.direct_indicator'
              defaultMessage='Private mention'
            />
          </div>
        )}
        <Link
          to={`/@${status.getIn(['account', 'acct'])}`}
          data-hover-card-account={status.getIn(['account', 'id'])}
          className='detailed-status__display-name'
        >
          <div className='detailed-status__display-avatar'>
            <Avatar account={status.get('account')} size={46} />
          </div>
          <DisplayName account={status.get('account')} localDomain={domain} />
          {withLogo && (
            <>
              <div className='spacer' />
              <IconLogo />
            </>
          )}
        </Link>

        {status.get('spoiler_text').length > 0 && (
          <ContentWarning
            text={
              status.getIn(['translation', 'spoilerHtml']) ||
              status.get('spoilerHtml')
            }
            expanded={expanded}
            onClick={handleExpandedToggle}
          />
        )}

        {expanded && (
          <>
            <StatusContent
              status={status}
              onTranslate={handleTranslate}
              {...(statusContentProps as any)}
            />

            {media}
            {hashtagBar}
          </>
        )}

        <div className='detailed-status__meta'>
          <div className='detailed-status__meta__line'>
            <a
              className='detailed-status__datetime'
              href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`}
              target='_blank'
              rel='noopener noreferrer'
            >
              <FormattedDate
                value={new Date(status.get('created_at') as string)}
                year='numeric'
                month='short'
                day='2-digit'
                hour='2-digit'
                minute='2-digit'
              />
            </a>

            {visibilityLink}
            {applicationLink}
          </div>

          {status.get('edited_at') && (
            <div className='detailed-status__meta__line'>
              <EditedTimestamp
                statusId={status.get('id')}
                timestamp={status.get('edited_at')}
              />
            </div>
          )}

          <div className='detailed-status__meta__line'>
            {reblogLink}
            {reblogLink && <>·</>}
            {favouriteLink}
          </div>
        </div>
      </div>
    </div>
  );
};
