import React, { useState, useMemo } from "react";
import { Formik } from "formik";
import { FormikHelpers } from "formik/dist/types";
import * as yup from "yup";

import { MediaGalleryModal as MediaGalleryModalComponent } from "@komi-app/creator-ui";

import { MediaGalleryItem } from "../../models/talent/talent-profile-module.model";
import { FLAGS, isOn, useFeatureIsOn } from "@komi-app/flags-sdk";
import { uploadImageToS3 } from "../../utils/photo";
import { isVideo, uploadMedia } from "utils/file";
import { addingHttpsPrefix } from "../../utils/string";

export interface MediaGalleryFormValues {
  file?: File;
  src?: string;
  thumbnailSrc?: string;
  caption?: string;
  originalFilename?: string;
  link?: string;
}

interface MediaGalleryModalProps {
  visible: boolean;
  onChangeVisible: (value: boolean) => void;
  existingItem?: MediaGalleryItem;
  onItemAdded: (data: MediaGalleryItem) => void;
  onItemEdited: (
    existingItem: MediaGalleryItem,
    newItem: MediaGalleryItem
  ) => void;
}

const allowedTypes = ["image/png", "image/jpeg", "image/webp"];

const allowedVideoTypes = [
  "video/quicktime",
  "video/mp4",
  "video/m4v",
  "video/mov",
  "video/avi",
];

const validateSchema = yup.object().shape({
  caption: yup.string().optional().max(256, "Maximum 256 characters"),
  link: yup.string().optional().url("Invalid link"),
  src: yup.string().required(),
  file: yup
    .mixed()
    .test({
      message: () => {
        if (isOn(FLAGS.FEAT_SB_637_ADD_VIDEOS_TO_MEDIA_GALLERY)) {
          return "File is invalid type, allowed types: png, jpeg, webp, mp4, m4v, mov, avi";
        }
        return "File is invalid type, allowed types: png, jpeg, webp";
      },
      test: (value) => {
        if (!value) {
          return true;
        }

        if (isOn(FLAGS.FEAT_SB_637_ADD_VIDEOS_TO_MEDIA_GALLERY)) {
          return [...allowedTypes, ...allowedVideoTypes].includes(value.type);
        }

        return allowedTypes.includes(value.type);
      },
    })
    .test({
      message: ({ value }) => {
        if (isOn(FLAGS.FEAT_SB_637_ADD_VIDEOS_TO_MEDIA_GALLERY)) {
          if (isVideo(value.name)) {
            return "File is too big, max 200 MB for videos";
          }
          return "File is too big, max 16 MB for images";
        }
        return "File is too big, max 16 MB";
      },
      test: (value) => {
        if (!value) {
          return true;
        }

        if (isOn(FLAGS.FEAT_SB_637_ADD_VIDEOS_TO_MEDIA_GALLERY)) {
          if (isVideo(value.name)) {
            return value.size <= 200 * 1000 * 1000;
          }
        }

        return value.size <= 16 * 1024 * 1024;
      },
    }),
});

const MediaGalleryModal: React.FC<MediaGalleryModalProps> = ({
  visible,
  existingItem,
  onChangeVisible,
  onItemAdded,
  onItemEdited,
}) => {
  const isVideosEnabled = useFeatureIsOn(
    FLAGS.FEAT_SB_637_ADD_VIDEOS_TO_MEDIA_GALLERY
  );
  const isLinkPrefixEnabled = useFeatureIsOn(
    FLAGS.FIX_SB_867_INCLUDE_PROTOCOL_PREFIX_MEDIA_GALLERY_LINK
  );
  const [uploading, setUploading] = useState<boolean>(false);
  const [fileType, setFileType] = useState<"image" | "video" | undefined>();
  const isUploadingVideo = uploading && fileType === "video";
  const initialValues = useMemo<MediaGalleryFormValues>(() => {
    if (existingItem) {
      return {
        src: existingItem.src,
        thumbnailSrc: existingItem.thumbnailSrc,
        originalFilename: existingItem.originalFilename,
        contentType: existingItem.contentType,
        caption: existingItem.caption,
        link: existingItem.url,
      };
    }

    return {
      src: undefined,
      thumbnailSrc: undefined,
      originalFilename: undefined,
      contentType: undefined,
      caption: undefined,
      link: undefined,
    };
  }, [existingItem]);

  const handleSubmit = async (
    values: MediaGalleryFormValues,
    formikHelpers: FormikHelpers<MediaGalleryFormValues>
  ) => {
    const isValid = await validateSchema.isValid(values);

    const { src, file } = values;

    if (!isValid || !src) {
      return;
    }

    const originalFilename = file?.name || existingItem?.originalFilename || "";
    const contentType = file?.type || existingItem?.contentType || "";

    const newItem = {
      src,
      thumbnailSrc: values.thumbnailSrc,
      originalFilename,
      contentType,
      caption: values.caption,
      url: values.link,
    };

    if (existingItem) {
      onItemEdited(existingItem, newItem);
    } else {
      onItemAdded({ ...newItem, order: 0, visible: true });
    }

    formikHelpers.resetForm();
  };

  return (
    <Formik
      initialValues={initialValues}
      onSubmit={handleSubmit}
      validationSchema={validateSchema}
      enableReinitialize
    >
      {(props) => (
        <MediaGalleryModalComponent
          onSubmit={props.handleSubmit}
          onCancel={() => {
            onChangeVisible(false);
            props.resetForm();
          }}
          media={
            props.values.src && isVideosEnabled
              ? {
                  src: props.values.thumbnailSrc || props.values.src,
                  name:
                    props.values.file?.name ||
                    existingItem?.originalFilename ||
                    "",
                }
              : props.values.src
                ? {
                    src:
                      props.values.src ||
                      window.URL.createObjectURL(props.values.file),
                    name:
                      props.values.file?.name ||
                      existingItem?.originalFilename ||
                      "",
                  }
                : undefined
          }
          mediaUploading={uploading}
          disabled={!props.values?.src}
          onMediaChange={async (file: File | null) => {
            if (isVideosEnabled) {
              // reset fields
              await props.setFieldValue("file", undefined, true);
              await props.setFieldValue("src", undefined, false);
              await props.setFieldValue("thumbnailSrc", undefined, false);
              setFileType(undefined);

              if (!file) {
                return;
              }

              const validationErrors = await props.setFieldValue(
                "file",
                file,
                true
              );

              const { file: fileErrors } = validationErrors || {};

              if (fileErrors) {
                props.setFieldValue("file", undefined, false);
                return;
              }

              setUploading(true);
              setFileType(isVideo(file.name) ? "video" : "image");

              try {
                const uploadedMedia = await uploadMedia(file);

                await props.setFieldValue("src", uploadedMedia.src, false);
                await props.setFieldValue(
                  "thumbnailSrc",
                  uploadedMedia.thumbnailSrc,
                  false
                );
                await props.setFieldValue(
                  "originalFilename",
                  uploadedMedia.originalFilename,
                  false
                );
              } catch (e) {
                props.setFieldError(
                  "file",
                  e?.message || "An unknown error occurred"
                );
              } finally {
                setUploading(false);
              }
            } else {
              // reset field
              props.setFieldValue("file", undefined, true);
              props.setFieldValue("src", undefined, false);
              props.setFieldValue("thumbnailSrc", undefined, false);

              if (!file) {
                return;
              }

              const validationErrors = await props.setFieldValue(
                "file",
                file,
                true
              );

              const { file: fileErrors } = validationErrors || {};

              if (fileErrors) {
                props.setFieldValue("file", undefined, false);
                return;
              }

              setUploading(true);

              try {
                props.setFieldValue("originalFilename", file.name, false);
                const url = await uploadImageToS3(file);

                props.setFieldValue("src", url, true);
              } catch (e) {
                props.setFieldError("file", e.message);
              } finally {
                setUploading(false);
              }
            }
          }}
          caption={props.values.caption}
          onCaptionChange={async (caption: string) => {
            if (isVideosEnabled) {
              await props.setFieldValue("caption", caption, false);
              await props.validateField("caption");
            } else {
              props.setFieldValue("caption", caption, true);
            }
          }}
          link={props.values.link}
          onLinkChange={(link: string) => {
            if (isLinkPrefixEnabled) {
              const linkWithProtocol = addingHttpsPrefix(link);
              props.setFieldValue("link", linkWithProtocol, false);
            } else {
              props.setFieldValue("link", link, false);
            }
          }}
          linkTypeFixed={isLinkPrefixEnabled}
          suggestedAllowedMediaTypes={
            isVideosEnabled
              ? [...allowedTypes, ...allowedVideoTypes]
              : allowedTypes
          }
          visible={visible}
          helpers={{
            media: isVideosEnabled
              ? isUploadingVideo
                ? "Uploading a large file, it might take a little longer"
                : "Upload an image (max 16 MB) or video (max 200 MB)"
              : "Upload an image, max 16 MB",
            caption: "Maximum 256 characters",
            link: "Optional",
          }}
          errors={{
            media: props.errors.file,
            caption: props.errors.caption,
            link: props.errors.link,
          }}
        />
      )}
    </Formik>
  );
};

export default MediaGalleryModal;
