import { css } from '@rocket.chat/css-in-js';
import { Box, ButtonGroup, ProgressBar } from '@rocket.chat/fuselage';
import type { ComponentProps } from 'react';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import type { Download } from '../../../downloads/common';
import { invoke } from '../../../ipc/renderer';
import ActionButton from './ActionButton';
import FileIcon from './FileIcon';

type DownloadItemProps = Download & ComponentProps<typeof Box>;

const DownloadItem = ({
  itemId,
  state,
  status: _status,
  fileName,
  receivedBytes,
  totalBytes,
  startTime,
  endTime,
  url: _url,
  mimeType,
  serverTitle,
  serverUrl: _serverUrl,
  savePath: _savePath,
  ...props
}: DownloadItemProps) => {
  const { t, i18n } = useTranslation();

  const progressSize = useMemo(() => {
    if (!receivedBytes || !totalBytes) {
      return undefined;
    }

    if (state === 'completed') {
      return i18n.format(totalBytes, 'byteSize');
    }

    return t('downloads.item.progressSize', {
      receivedBytes,
      totalBytes,
      ratio: receivedBytes / totalBytes,
    });
  }, [i18n, receivedBytes, state, t, totalBytes]);

  const progressSpeed = useMemo(() => {
    if (
      !receivedBytes ||
      !totalBytes ||
      !startTime ||
      !endTime ||
      state !== 'progressing'
    ) {
      return undefined;
    }

    return i18n.format(
      (receivedBytes / (endTime - startTime)) * 1000,
      'byteSpeed'
    );
  }, [endTime, i18n, receivedBytes, startTime, state, totalBytes]);

  const estimatedTimeLeft = useMemo(() => {
    if (
      !receivedBytes ||
      !totalBytes ||
      !startTime ||
      !endTime ||
      state !== 'progressing'
    ) {
      return undefined;
    }

    const remainingBytes = totalBytes - receivedBytes;
    const speed = receivedBytes / (endTime - startTime);
    return i18n.format(remainingBytes / speed, 'duration');
  }, [endTime, i18n, receivedBytes, startTime, state, totalBytes]);

  const handlePause = useCallback(() => {
    invoke('downloads/pause', itemId);
  }, [itemId]);

  const handleResume = useCallback(() => {
    invoke('downloads/resume', itemId);
  }, [itemId]);

  const handleCancel = useCallback(async () => {
    invoke('downloads/cancel', itemId);
  }, [itemId]);

  const handleShowInFolder = useCallback((): void => {
    invoke('downloads/show-in-folder', itemId);
  }, [itemId]);

  const handleRetry = useCallback(() => {
    invoke('downloads/retry', itemId);
  }, [itemId]);

  const handleRemove = useCallback(() => {
    invoke('downloads/remove', itemId);
  }, [itemId]);

  const handleCopyLink = useCallback(() => {
    invoke('downloads/copy-link', itemId);
  }, [itemId]);

  const errored = state === 'interrupted' || state === 'cancelled';
  const expired = state === 'expired';
  const percentage = useMemo(
    () => Math.floor((receivedBytes / totalBytes) * 100),
    [receivedBytes, totalBytes]
  );

  return (
    <Box
      width='100%'
      mbe='x16'
      pi='x8'
      pb='x8'
      borderRadius='x4'
      display='flex'
      alignItems='center'
      className={css`
        transition: background-color 0.15s ease;
        &:hover {
          background-color: var(--rcx-color-surface-hover);
        }
      `}
      {...props}
    >
      <Box
        width='x320'
        flexShrink={0}
        display='flex'
        flexDirection='row'
        alignItems='center'
      >
        <FileIcon fileName={fileName} mimeType={mimeType} />
        <Box flexGrow={1} mis='x12' minWidth={0}>
          <Box
            mbe='x4'
            color={errored || expired ? 'danger' : 'default'}
            fontScale='p1'
            withTruncatedText
          >
            {fileName}
          </Box>
          <Box color='hint' fontScale='c1' withTruncatedText>
            {serverTitle}
          </Box>
        </Box>
      </Box>

      <Box display='flex' flexDirection='column' flexGrow={1} mis='x16'>
        <Box
          display='flex'
          flexDirection='row'
          mbe='x8'
          alignItems='center'
          justifyContent='space-between'
        >
          <Box
            display='flex'
            flexDirection='row'
            alignItems='center'
            minWidth={0}
          >
            {progressSize ? (
              <Box mie='x16' color='hint' fontScale='c1' withTruncatedText>
                {progressSize}
              </Box>
            ) : null}
            {progressSpeed ? (
              <Box mie='x16' color='hint' fontScale='c1' withTruncatedText>
                {progressSpeed}
              </Box>
            ) : null}
            {estimatedTimeLeft ? (
              <Box color='hint' fontScale='c1' withTruncatedText>
                {estimatedTimeLeft}
              </Box>
            ) : null}
          </Box>
          <Box mis='x16'>
            <ButtonGroup small>
              {expired && (
                <ActionButton onClick={handleRemove}>
                  {t('downloads.item.remove')}
                </ActionButton>
              )}
              {!expired && (
                <ActionButton onClick={handleCopyLink}>
                  {t('downloads.item.copyLink')}
                </ActionButton>
              )}
              {state === 'progressing' && (
                <>
                  <ActionButton onClick={handlePause}>
                    {t('downloads.item.pause')}
                  </ActionButton>
                  <ActionButton onClick={handleCancel}>
                    {t('downloads.item.cancel')}
                  </ActionButton>
                </>
              )}
              {state === 'paused' && (
                <>
                  <ActionButton onClick={handleResume}>
                    {t('downloads.item.resume')}
                  </ActionButton>
                  <ActionButton onClick={handleCancel}>
                    {t('downloads.item.cancel')}
                  </ActionButton>
                </>
              )}
              {state === 'completed' && (
                <>
                  <ActionButton onClick={handleShowInFolder}>
                    {t('downloads.item.showInFolder')}
                  </ActionButton>
                  <ActionButton onClick={handleRemove}>
                    {t('downloads.item.remove')}
                  </ActionButton>
                </>
              )}
              {errored && (
                <>
                  <ActionButton danger onClick={handleRetry}>
                    {t('downloads.item.retry')}
                  </ActionButton>
                  <ActionButton onClick={handleRemove}>
                    {t('downloads.item.remove')}
                  </ActionButton>
                </>
              )}
            </ButtonGroup>
          </Box>
        </Box>
        <Box position='relative'>
          <ProgressBar
            percentage={percentage}
            error={errored ? t('downloads.item.errored') : undefined}
            // TODO: get complete file details, such as file-size from different cloud storages
            animated={percentage !== 100}
          />
        </Box>
      </Box>
    </Box>
  );
};

export default DownloadItem;
