import { AxiosResponse } from "axios";
import { useHTTP } from "hooks";
import { pond } from "protobuf-ts/pond";
import { useGlobalState } from "providers/StateContainer";
import { createContext, PropsWithChildren, useContext } from "react";
import { pondURL } from "./pond";

export interface toAttach {
  key: string;
  type: pond.ObjectType;
}

export interface IFileControllerAPI {
  uploadFiles: (
    files: FileList,
    toAttach?: toAttach,
    keys?: string[],
    types?: string[]
  ) => Promise<AxiosResponse<pond.AddFileResponse>>;
  listFileRefs: (
    objectKey: string,
    keys: string[],
    types: string[]
  ) => Promise<AxiosResponse<pond.ListFileRefsResponse>>;
  retrieveFile: (path: string) => Promise<any>;
  deleteFile: (fileID: string) => Promise<any>;
}

export const FileControllerAPIContext = createContext<IFileControllerAPI>({} as IFileControllerAPI);

export default function FileControllerProvider(props: PropsWithChildren<any>) {
  const { children } = props;
  const [{ as }] = useGlobalState();
  const { get, post, del, options } = useHTTP();

  const uploadFiles = (files: FileList, toAttach?: toAttach, keys?: string[], types?: string[]) => {
    let headers = { 
      ...options().headers,
      "Content-Type": "multipart/form-data"
    };
    let opt = { headers };
    let formData = new FormData();
    Array.from(files).forEach((f, i) => {
      formData.append("file" + i, f);
    });
    let url = pondURL(
      "/fileControl/upload" +
        (toAttach ? "?toAttach=" + toAttach.key + "&objectType=" + toAttach.type : "") +
        (keys ? "&keys=" + keys.join(",") : "") +
        (types ? "&types=" + types.join(",") : "")
    );
    if (as) {
      url = pondURL(
        "/fileControl/upload?as=" +
          as +
          (toAttach ? "&toAttach=" + toAttach.key + "&objectType=" + toAttach.type : "") +
          (keys ? "&keys=" + keys.join(",") : "") +
          (types ? "&types=" + types.join(",") : "")
      );
    }
    return post<pond.AddFileResponse>(url, formData, opt);
  };

  /**
   * Function to get the file references from the backend.
   * Note: the object key is what the files are attached to and not used for the permissions,
   * For example on a contract the files are linked to the transaction
   * however you would check the users permission to the contract
   * @param objectKey what the files are attached to
   * @param keys the key of the object you want to check permissions for
   * @param types the type of the object you want to check permissions for
   * @returns promise that contains a list of file references in the data
   */
  const listFileRefs = (objectKey: string, keys: string[], types: string[]) => {
    let url = pondURL(
      "/fileControl/list?objectKey=" +
        objectKey +
        "&keys=" +
        keys.join(",") +
        "&types=" +
        types.join(",")
    );
    if (as) {
      url = pondURL(
        "/fileControl/list?as=" +
          as +
          "&objectKey=" +
          objectKey +
          "&keys=" +
          keys.join(",") +
          "&types=" +
          types.join(",")
      );
    }
    return get<pond.ListFileRefsResponse>(url);
  };

  const retrieveFile = (path: string) => {
    let url = pondURL("/fileControl/retrieve?path=" + path);
    if (as) {
      url = pondURL("/fileControl/retrieve?as=" + as + "&path=" + path);
    }
    return get(url, { responseType: "blob" });
  };

  const deleteFile = (fileID: string) => {
    let url = pondURL("/fileControl/" + fileID + "/delete");
    if (as) {
      url = pondURL("/fileControl/" + fileID + "/delete?as=" + as);
    }
    return del(url, { responseType: "blob" });
  };

  return (
    <FileControllerAPIContext.Provider
      value={{
        uploadFiles,
        listFileRefs,
        retrieveFile,
        deleteFile
      }}>
      {children}
    </FileControllerAPIContext.Provider>
  );
}

export const useFileControllerAPI = () => useContext(FileControllerAPIContext);
