import {useTranslation} from 'react-i18next';
import {useController, useFormContext} from 'react-hook-form';
import {pick, types} from '@react-native-documents/picker';
import {Image, Video} from 'react-native-image-crop-picker';
import {useAttachmentPermissions} from '@hooks/useAttachmentsPermissions';
import {useGetAttachmentsLimit} from '@hooks/useGetAttachmentsLimit';
import {Attachment, AttachmentType} from '@interfaces/attachments';
import {uploadFileToS3} from '@services/multimedia';
import {ERROR} from '@shared/strings';
import {
  getUuid,
  openCamera,
  openGallery,
  uploadImage,
  uploadVideo,
} from '@shared/utils';

import {PublishPostField} from '../interfaces';

const isValidAttachment = (
  attachment: {size: Nullable<number>},
  attachmentsSize: number,
  maxAttachmentsSize: number,
) =>
  !!attachment.size && attachmentsSize + attachment.size <= maxAttachmentsSize;

export const useUploadAttachments = (
  onSetUploadingAttachment: (isUploading: boolean) => void,
) => {
  const {t} = useTranslation();
  const {setError} = useFormContext();
  const {requestCameraPermission} = useAttachmentPermissions();
  const {maxAttachmentsSize} = useGetAttachmentsLimit();

  const {
    field: {onChange: onChangeMultimedia, value: multimedia},
  } = useController({name: PublishPostField.Multimedia});
  const {
    field: {onChange: onChangeFiles, value: files},
  } = useController({name: PublishPostField.Files});
  const {
    field: {onChange: onChangeAttachmentsSize, value: attachmentsSize},
  } = useController({name: PublishPostField.AttachmentsSize});

  const attachmentIsValid = (result: Nullable<Image | Video>) => {
    if (!result || (!result.sourceURL && !result.path)) {
      return false;
    }

    if (!isValidAttachment(result, attachmentsSize, maxAttachmentsSize)) {
      setError(PublishPostField.AttachmentsSize, {message: 'MAX_SIZE_ERROR'});
      return false;
    }

    return true;
  };

  const onUploadImage = async (result: Nullable<Image>) => {
    if (!attachmentIsValid(result)) {
      return;
    }

    onSetUploadingAttachment(true);
    const newAttachment = await uploadImage(result!);
    onSetUploadingAttachment(false);

    if (newAttachment === ERROR) {
      return;
    }

    const attachment = {
      ...newAttachment,
      bytes: result!.size,
      id: getUuid(),
      name: `${t('general.image')}.${result!.mime.split('/')[1]}`,
    } as Attachment;

    onChangeMultimedia(multimedia.concat(attachment));
    onChangeAttachmentsSize(attachmentsSize + attachment.bytes!);
  };

  const onUploadVideo = async (result: Nullable<Video>) => {
    if (!attachmentIsValid(result)) {
      return;
    }
    onSetUploadingAttachment(true);
    const newAttachment = await uploadVideo({
      ...result!,
      path: (result!.sourceURL || result!.path).split('#')[0],
    });
    onSetUploadingAttachment(false);

    if (newAttachment === 'error') {
      return;
    }

    const attachment = {
      ...newAttachment,
      bytes: result!.size,
      id: getUuid(),
      name: `${t('general.video')}.${result!.mime.split('/')[1]}`,
    } as Attachment;

    onChangeMultimedia(multimedia.concat(attachment));
    onChangeAttachmentsSize(attachmentsSize + attachment.bytes!);
  };

  const openCameraWithPermission = async (type: 'photo' | 'video') => {
    const granted = await requestCameraPermission();
    if (!granted) {
      return;
    }

    return openCamera({
      options: {mediaType: type, forceJpg: type === 'photo'},
      save: onUploadImage,
      handleCancel: true,
    });
  };

  const onTakePicture = () => openCameraWithPermission('photo');

  const onTakeVideo = () => openCameraWithPermission('video');

  const onSelectPicture = () => {
    openGallery({
      options: {mediaType: 'photo', forceJpg: true},
      save: onUploadImage,
      handleCancel: true,
    });
  };

  const onSelectVideo = () => {
    openGallery({
      options: {mediaType: 'video'},
      save: result => onUploadVideo(result as Nullable<Video>),
      handleCancel: true,
    });
  };

  const onSelectDocument = async () => {
    const results = await pick({
      type: [
        types.pdf,
        types.zip,
        types.csv,
        types.doc,
        types.docx,
        types.json,
        types.plainText,
        types.ppt,
        types.pptx,
        types.xls,
        types.xlsx,
      ],
      allowMultiSelection: false,
    });
    const result = results[0];

    if (!result || !result?.name || !result?.size || !result?.type) {
      return;
    }

    if (!isValidAttachment(result, attachmentsSize, maxAttachmentsSize)) {
      setError(PublishPostField.AttachmentsSize, {message: 'MAX_SIZE_ERROR'});
      return;
    }

    onSetUploadingAttachment(true);
    const signedUrl = await uploadFileToS3({
      fileName: result.name,
      mime: result.type,
      type: AttachmentType.FILE,
      uri: result.uri,
    });
    onSetUploadingAttachment(false);

    if (signedUrl === ERROR) {
      return;
    }

    const attachment = {
      bytes: result.size,
      id: getUuid(),
      mime: result.type,
      name: result.name,
      path: result.uri,
      type: AttachmentType.FILE,
      url: signedUrl,
    } as Attachment;

    onChangeFiles(files.concat(attachment));
    onChangeAttachmentsSize(attachmentsSize + attachment.bytes!);
  };

  return {
    onSelectDocument,
    onSelectPicture,
    onSelectVideo,
    onTakePicture,
    onTakeVideo,
  };
};
