import { makeFetch } from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
import { PostStoreObjectSignature, StoredObject } from "../../types";

const algo = "AES-CBC";

const URL_POST = "/asyncupload/temp_url/generate/post";

const keyDefinition = {
  name: algo,
  length: 256,
};

const createFilename = (): string => {
  let text = "";
  const possible =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

  for (let i = 0; i < 7; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }

  return text;
};

/**
 * Fetches a new stored object from the server.
 *
 * @async
 * @function fetchNewStoredObject
 * @returns {Promise<StoredObject>} A Promise that resolves to the newly created StoredObject.
 */
export const fetchNewStoredObject = async (): Promise<StoredObject> => {
  return makeFetch("POST", "/api/1.0/doc-store/stored-object/create", null);
};

export const uploadVersion = async (
  uploadFile: ArrayBuffer,
  storedObject: StoredObject,
): Promise<string> => {
  const params = new URLSearchParams();
  params.append("expires_delay", "180");
  params.append("submit_delay", "180");
  const asyncData: PostStoreObjectSignature = await makeFetch(
    "GET",
    `/api/1.0/doc-store/async-upload/temp_url/${storedObject.uuid}/generate/post` +
      "?" +
      params.toString(),
  );
  const suffix = createFilename();
  const filename = asyncData.prefix + suffix;
  const formData = new FormData();
  formData.append("redirect", asyncData.redirect);
  formData.append("max_file_size", asyncData.max_file_size.toString());
  formData.append("max_file_count", asyncData.max_file_count.toString());
  formData.append("expires", asyncData.expires.toString());
  formData.append("signature", asyncData.signature);
  formData.append(filename, new Blob([uploadFile]), suffix);

  const response = await window.fetch(asyncData.url, {
    method: "POST",
    body: formData,
  });

  if (!response.ok) {
    console.error("Error while sending file to store", response);
    throw new Error(response.statusText);
  }

  return Promise.resolve(filename);
};

export const encryptFile = async (
  originalFile: ArrayBuffer,
): Promise<[ArrayBuffer, Uint8Array, JsonWebKey]> => {
  const iv = crypto.getRandomValues(new Uint8Array(16));
  const key = await window.crypto.subtle.generateKey(keyDefinition, true, [
    "encrypt",
    "decrypt",
  ]);
  const exportedKey = await window.crypto.subtle.exportKey("jwk", key);
  const encrypted = await window.crypto.subtle.encrypt(
    { name: algo, iv: iv },
    key,
    originalFile,
  );

  return Promise.resolve([encrypted, iv, exportedKey]);
};
