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

export interface IMineAPIContext {
  addMine: (mine: pond.MineSettings, otherTeam?: string) => Promise<AxiosResponse<pond.AddMineResponse>>;
  getMine: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.GetMineResponse>>;
  addDevice: (key: string, deviceID: string, permissions: pond.Permission[], otherTeam?: string) => Promise<any>;
  addComponent: (
    key: string,
    deviceID: string,
    componentKey: string,
    permissions: pond.Permission[],
    otherTeam?: string
  ) => Promise<any>;
  listMines: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.ListMinesResponse>>;
  listMinesSimple: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.ListMinesSimpleResponse>>;
  removeMine: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveMineResponse>>;
  updateMine: (
    mine: pond.MineSettings,
    componentPreferences: Map<string, pond.MineComponentPreferences>
  ) => Promise<AxiosResponse<pond.UpdateMineResponse>>;
}

export const MineAPIContext = createContext<IMineAPIContext>({} as IMineAPIContext);

interface Props {}

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

  const addMine = (mine: pond.MineSettings, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    return post<pond.AddMineResponse>(pondURL("/mines" + (view ? "?as=" + view : "")), mine);
  };

  const getMine = (key: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    return get<pond.GetMineResponse>(pondURL("/mines/" + key + (view ? "?as=" + view : "")));
  };

  const listMines = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    keys?: string,
    types?: string,
    otherTeam?: string
  ) => {
    const view = otherTeam ? otherTeam : as
    const url = pondURL(
      "/mines" +
        "?limit=" +
        limit +
        "&offset=" +
        offset +
        ("&order=" + (order ? order : "asc")) +
        ("&by=" + (orderBy ? orderBy : "deviceId")) +
        (search ? "&search=" + search : "") +
        (asRoot ? "&asRoot=" + asRoot.toString() : "") +
        (view ? "&as=" + view : "") +
        (keys ? "&keys=" + keys : "") +
        (types ? "&types=" + types : "")
    );
    return get<pond.ListMinesResponse>(url);
  };

  const listMinesSimple = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    otherTeam?: string
  ) => {
    const view = otherTeam ? otherTeam : as
    const url = pondURL(
      "/minesSimple" +
        "?limit=" +
        limit +
        "&offset=" +
        offset +
        ("&order=" + (order ? order : "asc")) +
        ("&by=" + (orderBy ? orderBy : "deviceId")) +
        (search ? "&search=" + search : "") +
        (asRoot ? "&asRoot=" + asRoot.toString() : "") +
        (view ? "&as=" + view : "")
    );
    return get<pond.ListMinesSimpleResponse>(url);
  };

  const removeMine = (key: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    return del<pond.RemoveMineResponse>(pondURL("/mines/" + key + (view ? "?as=" + view : "")));
  };

  const updateMine = (
    mine: pond.MineSettings,
    componentPreferences: Map<string, pond.MineComponentPreferences>
  ) => {
    let request = pond.UpdateMineRequest.create();
    let container = pond.MineComponentPreferencesContainer.create();
    request.settings = mine;
    //if (componentPreferences) {
    componentPreferences.forEach((pref, key) => {
      container.preferences.push(pref);
      container.keys.push(key);
    });
    request.componentPreferences = container;
    //}
    return put<pond.AddMineResponse>(pondURL("/mines"), request);
  };

  const addDevice = (key: string, deviceID: string, permissions: pond.Permission[], otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    if (view)
      return post(pondURL(`/mines/` + key + `/addDevice/` + deviceID + `?as=${view}`), {
        permissions: permissions.map(permission => permissionToString(permission))
      });
    return post(pondURL(`/mines/` + key + `/addDevice/` + deviceID), {
      permissions: permissions.map(permission => permissionToString(permission))
    });
  };

  const addComponent = (
    key: string,
    deviceID: string,
    componentKey: string,
    permissions: pond.Permission[],
    otherTeam?: string
  ) => {
    const view = otherTeam ? otherTeam : as
    if (view)
      return post(
        pondURL(`/mines/` + key + `/addComponent/` + deviceID + "/" + componentKey + `?as=${view}`),
        {
          permissions: permissions.map(permission => permissionToString(permission))
        }
      );
    return post(pondURL(`/mines/` + key + `/addComponent/` + deviceID + "/" + componentKey), {
      permissions: permissions.map(permission => permissionToString(permission))
    });
  };

  return (
    <MineAPIContext.Provider
      value={{
        addMine,
        getMine,
        addDevice,
        addComponent,
        listMines,
        listMinesSimple,
        removeMine,
        updateMine
      }}>
      {children}
    </MineAPIContext.Provider>
  );
}

export const useMineAPI = () => useContext(MineAPIContext);
