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 IFirmwareAPIContext {
  getFirmwareStatus: (deviceID: number | Long | string, demo?: boolean) => Promise<any>;
  cancelUpgrade: (deviceID: number | Long | string) => Promise<any>;
  getLatestFirmware: (
    platform: pond.DevicePlatform,
    channel: pond.UpgradeChannel,
    demo?: boolean
  ) => Promise<any>;
  getAllLatestFirmware: () => Promise<any>;
  listFirmware: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    settings?: string,
    status?: string
  ) => Promise<any>;
  removeFirmware: (platform: pond.DevicePlatform, version: string) => Promise<any>;
  downloadInstaller: (platform: pond.DevicePlatform, version: string) => Promise<any>;
  uploadFirmware: (
    version: string,
    channel: pond.UpgradeChannel,
    platform: pond.DevicePlatform,
    file: Blob,
    breaksStorage: boolean
  ) => Promise<any>;
  updateChannel: (
    platform: pond.DevicePlatform,
    version: string,
    channel: pond.UpgradeChannel
  ) => Promise<any>;
  upgradeFirmware: (device: number | string) => Promise<any>;
}

export const FirmwareAPIContext = createContext<IFirmwareAPIContext>({} as IFirmwareAPIContext);

interface Props {}

function platformRequest(platform: pond.DevicePlatform): string {
  return platformBody(platform)
    .toString()
    .replace("DEVICE_PLATFORM_", "")
    .toLowerCase();
}

function channelRequest(channel: pond.UpgradeChannel): string {
  return channelBody(channel)
    .replace("UPGRADE_CHANNEL_", "")
    .toLowerCase();
}

function platformBody(platform: pond.DevicePlatform): string {
  return pond.DevicePlatform[platform].toString();
}

function channelBody(channel: pond.UpgradeChannel): string {
  return pond.UpgradeChannel[channel].toString();
}

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

  const getFirmwareStatus = (deviceID: number | Long | string, demo: boolean = false) => {
    return get(pondURL("/devices/" + deviceID.toString() + "/firmware", demo));
  };

  const cancelUpgrade = (deviceID: number | Long | string) => {
    return post(pondURL("/devices/" + deviceID.toString() + "/cancelUpgrade"));
  };

  const getLatestFirmware = (
    platform: pond.DevicePlatform,
    channel: pond.UpgradeChannel,
    demo: boolean = false
  ) => {
    return get(
      pondURL(
        "/firmware/latest?platform=" +
          platformRequest(platform) +
          "&channel=" +
          channelRequest(channel),
        demo
      )
    );
  };

  const getAllLatestFirmware = () => {
    return get(pondURL("/firmware/all"));
  };

  const listFirmware = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    settings?: string,
    status?: string
  ) => {
    return get(
      pondURL(
        "/firmware" +
          "?limit=" +
          limit +
          "&offset=" +
          offset +
          ("&order=" + (order ? order : "asc")) +
          ("&by=" + (orderBy ? orderBy : "uploaded")) +
          (search ? "&search=" + search : "") +
          (settings ? "&settings=" + settings : "") +
          (status ? "&status=" + status : "")
      )
    );
  };

  const removeFirmware = (platform: pond.DevicePlatform, version: string) => {
    return del(pondURL("/firmware/" + platformRequest(platform) + "/" + version));
  };

  const downloadInstaller = (platform: pond.DevicePlatform, version: string) => {
    let headers = {
      Accept: "application/octet-stream",
      ...options().headers
    };
    headers = { ...headers, ...options().headers };
    let opt = {
      responseType: "arraybuffer",
      headers: headers
    };
    return get(
      pondURL("/firmware/download?platform=" + platformRequest(platform) + "&version=" + version),
      opt as any
    );
  };

  const uploadFirmware = (
    version: string,
    channel: pond.UpgradeChannel,
    platform: pond.DevicePlatform,
    file: Blob,
    breaksStorage: boolean
  ) => {
    let headers = { 
      ...options().headers,
      "Content-Type": "multipart/form-data"
    };
    let opt = { headers };
    let data = new FormData();
    data.append("version", version);
    data.append("channel", channelBody(channel));
    data.append("platform", platformBody(platform));
    data.append("file", file);
    data.append("breaksStorage", breaksStorage.toString());
    console.log(data)
    return post(pondURL("/firmware"), data, opt);
  };

  const updateChannel = (
    platform: pond.DevicePlatform,
    version: string,
    channel: pond.UpgradeChannel
  ) => {
    return put(pondURL("/firmware/channel"), {
      platform: platformBody(platform),
      version: version,
      channel: channelBody(channel)
    });
  };

  const upgradeFirmware = (device: number | string) => {
    return post(pondURL("/devices/" + device + "/upgrade" + (as ? "?as=" + as : "")), {});
  };

  return (
    <FirmwareAPIContext.Provider
      value={{
        getFirmwareStatus,
        cancelUpgrade,
        getLatestFirmware,
        getAllLatestFirmware,
        listFirmware,
        removeFirmware,
        downloadInstaller,
        uploadFirmware,
        updateChannel,
        upgradeFirmware
      }}>
      {children}
    </FirmwareAPIContext.Provider>
  );
}

export const useFirmwareAPI = () => useContext(FirmwareAPIContext);
