import React, {useMemo, useState} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import {
  Title,
  HuGoFile,
  Uploader,
  Typography,
  CardContainer,
} from '@components';
import {SetState} from '@interfaces/generic';
import {Attachment} from '@interfaces/attachments';
import Item from '@modules/timeOff/components/Item';
import {showSnackbar} from '@redux/dispatchers';
import {sizeToBytes} from '@shared/utils';
import {useTheme} from '@shared/theme';

import {MAX_ATTACHMENTS_SIZE, MAX_SIZE_STRING} from './constants';
import {styles} from './styles';
import {transformAttachments, uploadAttachments} from './utils';

const UNLIMITED_LINES = 0;

interface Props {
  addAttachments: (attachments: Attachment[]) => void;
  canDownloadAttachments?: boolean;
  canUploadAttachments?: boolean;
  hasError?: boolean;
  initialAttachments: Nullable<Attachment[]>;
  instructions: Nullable<string>;
  loadingAttachments: boolean;
  removeAttachment: (attachmentId: string) => void;
  setLoadingAttachments: SetState<boolean>;
  showDeleteButton?: boolean;
  wrapInCard?: boolean;
}

function Documentation({
  addAttachments,
  canDownloadAttachments,
  canUploadAttachments = true,
  hasError,
  initialAttachments,
  instructions,
  loadingAttachments,
  removeAttachment,
  setLoadingAttachments,
  showDeleteButton = true,
  wrapInCard = false,
}: Props) {
  const {t} = useTranslation();
  const {theme} = useTheme();
  const [attachments, setAttachments] = useState<HuGoFile[]>(
    transformAttachments(initialAttachments),
  );
  const attachmentsSize = useMemo(
    () =>
      initialAttachments?.reduce<number>(
        (size, item) => size + (item.bytes || sizeToBytes(item.size)),
        0,
      ) || 0,
    [initialAttachments],
  );

  const onUploadAttachments = async (newAttachments: HuGoFile[]) => {
    const newAttachmentsSize = newAttachments.reduce<number>(
      (sum, item) => sum + item.size,
      attachmentsSize,
    );
    if (newAttachmentsSize > MAX_ATTACHMENTS_SIZE) {
      showSnackbar({title: t('general.max_size_error'), variant: 'error'});
      return;
    }
    setLoadingAttachments(true);
    setAttachments(prev => [...prev, ...newAttachments]);
    const {uploadedAttachments, errorAttachments} = await uploadAttachments(
      newAttachments,
    );
    if (uploadedAttachments.length) {
      addAttachments(uploadedAttachments);
    }
    setAttachments(prev =>
      prev.map(attachment => ({
        ...attachment,
        hasError:
          attachment.hasError ||
          errorAttachments.some(
            errorAttachment => errorAttachment.id === attachment.id,
          ),
        isUploading: false,
      })),
    );
    setLoadingAttachments(false);
  };

  const onRemoveAttachment = (attachmentId: string) => {
    removeAttachment(attachmentId);
    setAttachments(prev => prev.filter(a => a.id !== attachmentId));
  };

  const uploader = (
    <Uploader
      canDownloadFile={canDownloadAttachments}
      description={t('time_off.allowed_formats', {
        maxSize: MAX_SIZE_STRING,
      })}
      disabled={loadingAttachments}
      files={attachments}
      helper={hasError ? t('time_off.uploading_required_error') : undefined}
      inputStyle={styles.uploader}
      isError={hasError}
      onDeleteFile={
        canUploadAttachments && showDeleteButton
          ? onRemoveAttachment
          : undefined
      }
      multiFiles={canUploadAttachments}
      onPickFiles={onUploadAttachments}
      showCheckIcon={!canDownloadAttachments}
      title={t('time_off.upload_document')}
      variant="input"
    />
  );

  const content = (
    <View style={styles.gap}>
      {wrapInCard ? (
        <Item title={t('time_off.documentation')}>
          {!!instructions && (
            <Typography variant="s">{instructions}</Typography>
          )}
          {uploader}
        </Item>
      ) : (
        <>
          <Title
            description={instructions || undefined}
            descriptionNumberOfLines={UNLIMITED_LINES}
            size="s"
            title={t('time_off.documentation')}
          />
          {uploader}
        </>
      )}
    </View>
  );

  return wrapInCard ? (
    <CardContainer style={{backgroundColor: theme.background.elements.grey}}>
      {content}
    </CardContainer>
  ) : (
    content
  );
}

export default Documentation;
