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";
import { or } from "utils";

export interface IGrainInterface {
  addGrain: (
    settings: pond.GrainSettings,
    otherTeam?: string
  ) => Promise<AxiosResponse<pond.AddGrainResponse>>;
  getGrain: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.GetGrainResponse>>
  listGrains: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    keys?: string[],
    types?: string[],
    otherTeam?: string,
  ) => Promise<AxiosResponse<pond.ListGrainsResponse>>;
  updateGrain: (key: string, settings: pond.GrainSettings, otherTeam?: string) => Promise<AxiosResponse<pond.UpdateGrainResponse>>
  removeGrain: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveGrainResponse>>;
}

export const GrainAPIcontext = createContext<IGrainInterface>({} as IGrainInterface);

interface Props {}

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

  //add
  const addGrain = (settings: pond.GrainSettings, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    if (view) {
      return post<pond.AddGrainResponse>(
        pondURL("/grains?&as=" + view),
        settings
      );
    }
    return post<pond.AddGrainResponse>(pondURL("/grains"), settings);
  };

  //get 
  const getGrain = (key: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    const url = "/grains/" + key + (view ? "?as=" + view : "")
    return new Promise<AxiosResponse<pond.GetGrainResponse>>((resolve, reject)=>{
      get<pond.GetGrainResponse>(pondURL(url))
      .then(resp => {
        if (resp.data.grain){
          resp.data.grain = pond.GrainObject.fromObject(resp.data.grain)
        }
        resolve(resp)
      })
      .catch(err => {
        reject(err)
      })
    }) 
  }
  //list
  const listGrains = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    keys?: string[],
    types?: string[],
    otherTeam?: string
  ) => {
    return new Promise<AxiosResponse<pond.ListGrainsResponse>>((resolve, reject)=>{
        const view = otherTeam ? otherTeam : as
          get<pond.ListGrainsResponse>(
            pondURL(
              "/grains?limit=" +
                limit +
                "&offset=" +
                offset +
                ("&order=" + or(order, "asc")) +
                ("&by=" + or(orderBy, "key")) +
                (search ? "&search=" + search : "") +
                (keys ? "&keys=" + keys.join(",") : "") +
                (types ? "&types=" + types.join(",") : "") +
                (view ? "&as=" + view : "")
            )
          ).then(resp => {
            resp.data = pond.ListGrainsResponse.fromObject(resp.data);
            return resolve(resp)
          }).catch(err => {
            return reject(err)
          })
        })
  };

  //update
  const updateGrain = (key: string, settings: pond.GrainSettings, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    if (view) {
      return put<pond.UpdateGrainResponse>(
        pondURL("/grains/"+ key + "?&as=" + view),
        settings
      );
    }
    return put<pond.UpdateGrainResponse>(pondURL("/grains/" + key), settings);
  }

  //remove
  const removeGrain = (key: string, otherTeam?: string) => {
    const view = otherTeam ? otherTeam : as
    if (view) {
      return del<pond.RemoveGrainResponse>(pondURL("/grains/" + key + "?as=" + view));
    }
    return del<pond.RemoveGrainResponse>(pondURL("/grains/" + key));
  };

  return (
    <GrainAPIcontext.Provider
      value={{
        addGrain,
        getGrain,
        listGrains,
        updateGrain,
        removeGrain
      }}>
      {children}
    </GrainAPIcontext.Provider>
  );
}

export const useGrainAPI = () => useContext(GrainAPIcontext);