import axios from "axios";
import env from "../env";
import { client } from "../graphql/client";
import { INSERT_NEW_DOCUMENT } from "../graphql/documents.queries";
import { axiosAuthInterceptorId } from "./CleanAxios";
import * as MediaLibrary from "expo-media-library";
import { gql } from "@apollo/client";

//Context: currentUserEmail, bodyshop, jobid, invoiceid

//Required to prevent headers from getting set and rejected from Cloudinary.
var cleanAxios = axios.create();
cleanAxios.interceptors.request.eject(axiosAuthInterceptorId);

export const handleUpload = async (ev, context) => {
  const { filename, mediaId, onError, onSuccess, onProgress } = ev;
  const { bodyshop, jobId } = context;

  const imageData = await MediaLibrary.getAssetInfoAsync(mediaId);
  const newFile = await (await fetch(imageData.localUri)).blob();
  let extension = imageData.localUri.split(".").pop();
  let key = `${bodyshop.id}/${jobId}/${(filename || newFile.data.name).replace(
    /\.[^/.]+$/,
    ""
  )}-${new Date().getTime()}`;

  const res = await uploadToCloudinary(
    key,
    mediaId,
    imageData,
    extension,
    newFile.type,
    newFile,
    onError,
    onSuccess,
    onProgress,
    context
  );
  return res;
};

export const uploadToCloudinary = async (
  key,
  mediaId,
  imageData,
  extension,
  fileType,
  file,
  onError,
  onSuccess,
  onProgress,
  context
) => {
  const { bodyshop, jobId, billId, uploaded_by, callback, tagsArray, photo } =
    context;

  //Set variables for getting the signed URL.
  let timestamp = Math.floor(Date.now() / 1000);
  let public_id = key;
  let tags = `${bodyshop.textid},${
    tagsArray ? tagsArray.map((tag) => `${tag},`) : ""
  }`;
  //  let eager = process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS;

  const upload_preset = fileType.startsWith("video")
    ? "incoming_upload_video"
    : "incoming_upload";

  //Get the signed url.

  let signedURLResponse;
  try {
    signedURLResponse = await axios.post(`${env.API_URL}/media/sign`, {
      public_id: public_id,
      tags: tags,
      timestamp: timestamp,

      upload_preset: upload_preset,
    });
  } catch (error) {
    console.log("ERROR GETTING SIGNED URL", error);
    return { success: false, error: error };
  }

  if (signedURLResponse.status !== 200) {
    console.log("Error Getting Signed URL", signedURLResponse.statusText);
    if (onError) onError(signedURLResponse.statusText);

    return { success: false, error: signedURLResponse.statusText };
  }

  //Build request to end to cloudinary.

  var signature = signedURLResponse.data;
  var options = {
    headers: { "X-Requested-With": "XMLHttpRequest" },
    onUploadProgress: (e) => {
      if (onProgress)
        onProgress({ percent: e.loaded / e.total, loaded: e.loaded });
    },
  };

  const formData = new FormData();
  formData.append("file", {
    uri: imageData.localUri,
    type: fileType,
    name: file.data.name,
  });
  formData.append("upload_preset", upload_preset);
  formData.append("api_key", env.REACT_APP_CLOUDINARY_API_KEY);
  formData.append("public_id", public_id);
  formData.append("tags", tags);
  formData.append("timestamp", timestamp);
  formData.append("signature", signature);

  //Upload request to Cloudinary
  let cloudinaryUploadResponse;
  try {
    cloudinaryUploadResponse = await cleanAxios.post(
      `${env.REACT_APP_CLOUDINARY_ENDPOINT_API}/${DetermineFileType(
        fileType
      )}/upload`,
      formData,
      {
        ...options,
      }
    );
    // console.log("Cloudinary Upload Response", cloudinaryUploadResponse.data);
  } catch (error) {
    console.log("CLOUDINARY error", error.response, cloudinaryUploadResponse);
    return { success: false, error: error };
  }

  if (cloudinaryUploadResponse.status !== 200) {
    console.log(
      "Error uploading to cloudinary.",
      cloudinaryUploadResponse.statusText,
      cloudinaryUploadResponse
    );
    if (onError) onError(cloudinaryUploadResponse.statusText);
    return { success: false, error: cloudinaryUploadResponse.statusText };
  }

  //Insert the document with the matching key.
  const documentInsert = await client.mutate({
    mutation: INSERT_NEW_DOCUMENT,

    update: (cache, { data }) => {
      cache.modify({
        fields: {
          documents: (existingDocs = []) => {
            const newDocRef = cache.writeFragment({
              data: data.insert_documents.returning[0],
              fragment: gql`
                fragment newDoc on documents {
                  id
                  name
                  key
                  type
                  takenat
                  extension
                  jobid
                }
              `,
            });
            return [...existingDocs, newDocRef];
          },
        },
      });
    },
    variables: {
      docInput: [
        {
          ...(jobId ? { jobid: jobId } : {}),
          ...(billId ? { billid: billId } : {}),
          uploaded_by: uploaded_by,
          key: key,
          type: fileType,
          extension: extension,
          bodyshopid: bodyshop.id,
          size: cloudinaryUploadResponse.data.bytes || file.size,
          ...(imageData.creationTime
            ? { takenat: new Date(imageData.creationTime) }
            : {}),
        },
      ],
    },
  });
  if (!documentInsert.errors) {
    if (onSuccess)
      onSuccess({
        uid: documentInsert.data.insert_documents.returning[0].id,
        name: documentInsert.data.insert_documents.returning[0].name,
        status: "done",
        key: documentInsert.data.insert_documents.returning[0].key,
      });
    // notification["success"]({
    //   message: i18n.t("documents.successes.insert"),
    // });
    if (callback) {
      callback();
    }
  } else {
    if (onError) onError(JSON.stringify(documentInsert.errors));
    // notification["error"]({
    //   message: i18n.t("documents.errors.insert", {
    //     message: JSON.stringify(JSON.stringify(documentInsert.errors)),
    //   }),
    // });
    return {
      success: false,
      error: JSON.stringify(documentInsert.errors),
      mediaId,
    };
  }

  return { success: true, mediaId };
};

export function DetermineFileType(filetype) {
  if (!filetype) return "auto";
  else if (filetype.startsWith("image")) return "image";
  else if (filetype.startsWith("video")) return "video";
  else if (filetype.startsWith("application/pdf")) return "image";
  else if (filetype.startsWith("application")) return "raw";

  return "auto";
}

export function formatBytes(a, b = 2) {
  if (0 === a || !a) return "0 Bytes";
  const c = 0 > b ? 0 : b,
    d = Math.floor(Math.log(a) / Math.log(1024));
  return (
    parseFloat((a / Math.pow(1024, d)).toFixed(c)) +
    " " +
    ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][d]
  );
}
