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

export interface IGateInterface {
  addGate: (
    name: string,
    settings: pond.GateSettings,
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.AddGateResponse>>;
  listGates: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    pcaStatus?: boolean,
    keys?: string[],
    types?: string[],
    numerical?: boolean,
    specificUser?: string,
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.ListGatesResponse>>;
  updateGate: (
    key: string,
    name: string,
    settings: pond.GateSettings,
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.UpdateGateResponse>>;
  getGate: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.GetGateResponse>>;
  removeGate: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveGateResponse>>;
  updateLink: (
    parentKey: string,
    parentType: string,
    objectID: string,
    objectType: string,
    permissions: string[],
    otherTeam?: string
  ) => Promise<any>;
  updatePrefs: (
    gateKey: string,
    childType: string,
    childKey: string,
    gatePref: pond.GateComponentType | pond.GateDeviceType,
    keys?: string[],
    types?: string[],
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.UpdateGatePreferencesResponse>>;
  getGatePageData: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.GetGatePageDataResponse>>;
  listGateAirflow: (
    gate: string,
    device: number | string,
    ambientComponent: string,
    pressureComponent: string,
    start: string,
    end: string,
    keys?: string[],
    types?: string[],
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.ListGateAirflowResponse>>;
  listGateFlowEvents: (
    gate: string,
    device: number | string,
    ambientComponent: string,
    pressureComponent: string,
    start: string,
    end: string,
    idleFlow: number,
    flowVariance: number,
    keys?: string[],
    types?: string[],
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.ListGateFlowEventsResponse>>;
  listGateMeasurements: (
    key: string,
    start: string,
    end: string,
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.ListGateMeasurementsResponse>>;
}

export const GateAPIcontext = createContext<IGateInterface>({} as IGateInterface);

interface Props {}

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

  const addGate = (name: string, settings: pond.GateSettings, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    let url = pondURL("/gates?name=" + name + (view ? "&as=" + view : ""))
    return new Promise<AxiosResponse<pond.AddGateResponse>>((resolve, reject) => {
      post<pond.AddGateResponse>(url, settings).then(resp => {
        resp.data = pond.AddGateResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const listGates = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    pcaStatus?: boolean,
    keys?: string[],
    types?: string[],
    numerical?: boolean,
    specificUser?: string,
    otherTeam?: string
  ) => {
    let asText = "";
    const view = otherTeam ? otherTeam : as
    if (view) asText = "&as=" + view;
    if (specificUser) asText = "&as=" + specificUser;
    let url = pondURL(
      "/gates?limit=" +
        limit +
        "&offset=" +
        offset +
        ("&order=" + (order ? order : "asc")) +
        ("&by=" + (orderBy ? orderBy : "key")) +
        (numerical ? "&numerical=true" : "") +
        (search ? "&search=" + search : "") +
        (pcaStatus ? "&getPCA=" + pcaStatus.toString() : "") +
        (keys ? "&keys=" + keys.toString() : "") +
        (types ? "&types=" + types.toString() : "") +
        asText
    )
    return new Promise<AxiosResponse<pond.ListGatesResponse>>((resolve, reject) => {
      get<pond.ListGatesResponse>(url).then(resp => {
        resp.data = pond.ListGatesResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const updateGate = (key: string, name: string, settings: pond.GateSettings, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    let url = pondURL("/gates/" + key + "?name=" + name + (view ? "&as=" + view : ""))
    return new Promise<AxiosResponse<pond.UpdateGateResponse>>((resolve, reject) => {
      put<pond.UpdateGateResponse>(url, settings).then(resp => {
        resp.data = pond.UpdateGateResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const removeGate = (key: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    let url = pondURL("/gates/" + key + (view ? "?as=" + view : ""))
    return new Promise<AxiosResponse<pond.RemoveGateResponse>>((resolve, reject) => {
      del<pond.RemoveGateResponse>(url).then(resp => {
        resp.data = pond.RemoveGateResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const getGate = (key: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    let url = pondURL("/gates/" + key + (view ? "?as=" + view : ""))
    return new Promise<AxiosResponse<pond.GetGateResponse>>((resolve, reject) => {
      get<pond.GetGateResponse>(url).then(resp => {
        resp.data = pond.GetGateResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const getGatePageData = (key: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    let url = pondURL("/gatePage/" + key + (view ? "?as=" + view : ""))
    return new Promise<AxiosResponse<pond.GetGatePageDataResponse>>((resolve, reject) => {
      get<pond.GetGatePageDataResponse>(url).then(resp => {
        resp.data = pond.GetGatePageDataResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const updateLink = (
    parentID: string,
    parentType: string,
    objectID: string,
    objectType: string,
    permissions: string[],
    otherTeam?: string
  ) => {
    const view = otherTeam ? otherTeam : as
    let url = pondURL(`/gates/` + parentID + "/link" + (view ? `?as=${view}` : ""))
    return new Promise<AxiosResponse>((resolve, reject) => {
      post(url, {
        Key: objectID,
        Type: objectType,
        Parent: parentID,
        ParentType: parentType,
        Permissions: permissions
      }).then(resp => {
        resolve(resp)
      }).catch(err => {
        reject(err)
      })
    })

  };

  const updatePrefs = (
    gateKey: string,
    childType: string,
    childKey: string,
    gatePref: pond.GateComponentType | pond.GateDeviceType,
    keys?: string[],
    types?: string[],
    otherTeam?: string
  ) => {
    const view = otherTeam ? otherTeam : as
    let url =         pondURL(
      `/gatePrefs/` +
        gateKey +
        "?childType=" +
        childType +
        "&childKey=" +
        childKey +
        "&gatePreference=" +
        gatePref +
        (view ? `&as=` + view : "") +
        (keys ? "&keys=" + keys.toString() : "") +
        (types ? "&types=" + types.toString() : "")
    )
    return new Promise<AxiosResponse<pond.UpdateGatePreferencesResponse>>((resolve, reject) => {
      put<pond.UpdateGatePreferencesResponse>(url).then(resp => {
        resp.data = pond.UpdateGatePreferencesResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const listGateAirflow = (
    gate: string,
    device: number | string,
    ambientComponent: string,
    pressureComponent: string,
    start: string,
    end: string,
    keys?: string[],
    types?: string[],
    otherTeam?: string
  ) => {
    const view = otherTeam ? otherTeam : as
    let url =       pondURL(
      "/gates/" +
        gate +
        "/airflow?device=" +
        device +
        "&ambient=" +
        ambientComponent +
        "&pressure=" +
        pressureComponent +
        "&start=" +
        start +
        "&end=" +
        end +
        (view ? "&as=" + view : "") +
        (keys ? "&keys=" + keys.toString() : "") +
        (types ? "&types=" + types.toString() : "")
    )
    return new Promise<AxiosResponse<pond.ListGateAirflowResponse>>((resolve, reject) => {
      get<pond.ListGateAirflowResponse>(url).then(resp => {
        resp.data = pond.ListGateAirflowResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const listGateMeasurements = (key: string, start: string, end: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    let url = pondURL("/gates/" + key + "/measurements?start=" + start + "&end=" + end + "&as=" + view)
    return new Promise<AxiosResponse<pond.ListGateMeasurementsResponse>>((resolve, reject) => {
      get<pond.ListGateMeasurementsResponse>(url).then(resp => {
        resp.data = pond.ListGateMeasurementsResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const listGateFlowEvents = (
    gate: string,
    device: number | string,
    ambientComponent: string,
    pressureComponent: string,
    start: string,
    end: string,
    idleFlow: number,
    flowVariance: number,
    keys?: string[],
    types?: string[],
    otherTeam?: string
  ) => {
    const view = otherTeam ? otherTeam : as
    return get<pond.ListGateFlowEventsResponse>(
      pondURL(
        "/gates/" +
          gate +
          "/airflowEvents?device=" +
          device +
          "&ambient=" +
          ambientComponent +
          "&pressure=" +
          pressureComponent +
          "&start=" +
          start +
          "&end=" +
          end +
          "&idle=" +
          idleFlow +
          "&variance=" +
          flowVariance +
          (view ? "&as=" + view : "") +
          (keys ? "&keys=" + keys.toString() : "") +
          (types ? "&types=" + types.toString() : "")
      )
    );
  };

  return (
    <GateAPIcontext.Provider
      value={{
        addGate,
        listGates,
        updateGate,
        removeGate,
        getGate,
        updateLink,
        getGatePageData,
        updatePrefs,
        listGateAirflow,
        listGateMeasurements,
        listGateFlowEvents
      }}>
      {children}
    </GateAPIcontext.Provider>
  );
}

export const useGateAPI = () => useContext(GateAPIcontext);
