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

export interface ITeamAPIContext {
  addTeam: (team: pond.TeamSettings) => Promise<AxiosResponse<pond.AddTeamResponse>>;
  getTeam: (teamID: string, scope?: Scope) => Promise<Team>;
  updateTeam: (
    key: string,
    team: pond.TeamSettings,
    asRoot?: boolean
  ) => Promise<AxiosResponse<pond.UpdateTeamResponse>>;
  updatePreferences: (
    key: string,
    preferences: pond.TeamPreferences,
    keys?: string[],
    types?: string[]
  ) => Promise<any>;
  listTeams: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    otherTeam?: string,
    prefixSearch?: string,
  ) => Promise<AxiosResponse<pond.ListTeamsResponse>>;
  listAllTeams: () => Promise<AxiosResponse<pond.ListTeamsResponse>>;
  listObjectTeams: (scope: Scope, otherTeam?: string) => Promise<any>;
  removeTeam: (key: string) => Promise<AxiosResponse<pond.RemoveTeamResponse>>;
}

export const TeamAPIContext = createContext<ITeamAPIContext>({} as ITeamAPIContext);

interface Props {}

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

  const addTeam = (team: pond.TeamSettings) => {
    return new Promise<AxiosResponse<pond.AddTeamResponse>>((resolve, reject) => {
      post<pond.AddTeamResponse>(pondURL("/team"), team).then(resp => {
        resp.data = pond.AddTeamResponse.fromObject(resp.data)
        resolve(resp)
      }).catch(err => {
        reject(err)
      })
    })
  };

  const getTeam = (id: string, scope?: Scope): Promise<Team> => {
    let partial = "/team/" + id;
    if (scope) {
      partial += "?kind=" + scope.kind + "&key=" + scope.key;
    }
    return new Promise(function(resolve, reject) {
      get(pondURL(partial))
        .then((response: any) => resolve(Team.any(response.data)))
        .catch((error: any) => reject(error));
    });
  };

  const removeTeam = (key: string) => {
    return new Promise<AxiosResponse<pond.RemoveTeamResponse>>((resolve, reject) => {
      del<pond.RemoveTeamResponse>(pondURL("/teams/" + key)).then(resp => {
        resp.data = pond.RemoveTeamResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const updateTeam = (key: string, team: pond.TeamSettings, asRoot?: boolean) => {
    return new Promise<AxiosResponse<pond.UpdateTeamResponse>>((resolve, reject) => {
      put<pond.UpdateTeamResponse>(
        pondURL("/teams/" + key + (asRoot ? "?asRoot=" + asRoot.toString() : "")),
        team
      ).then(resp => {
        resp.data = pond.UpdateTeamResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const updatePreferences = (
    key: string,
    preferences: pond.TeamPreferences,
    // keys?: string[],
    // types?: string[]
  ) => {
    return new Promise<AxiosResponse>((resolve, reject) => {
      put(pondURL("/teams/" + key + "/preferences"), preferences).then(resp => {
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const listTeams = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    otherTeam?: string,
    prefixSearch?: string,
  ) => {
    //let asText = team ? "&as=" + team.key() : "";
    const view = otherTeam ? otherTeam : as
    let url = pondURL(
      "/teams" +
        "?limit=" +
        limit +
        "&offset=" +
        offset +
        ("&order=" + or(order, "asc")) +
        ("&by=" + or(orderBy, "key")) +
        (search ? "&search=" + search : "") +
        (prefixSearch ? "&prefixSearch=" + prefixSearch : "") +
        (asRoot ? "&asRoot=" + asRoot.toString() : "") +
        (view ? "&as=" + view : "")
    )
    return new Promise<AxiosResponse<pond.ListTeamsResponse>>((resolve, reject)=>{
      get<pond.ListTeamsResponse>(url).then(resp => {
        resp.data = pond.ListTeamsResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    }) 
  };

  const listAllTeams = () => {
    return new Promise<AxiosResponse<pond.ListTeamsResponse>>((resolve, reject) => {
      get<pond.ListTeamsResponse>(pondURL("/allTeams")).then(resp => {
        resp.data = pond.ListTeamsResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const listObjectTeams = (scope: Scope, otherTeam?: string) => {
    let url = "/" + scope.kind + "s/" + scope.key + "/teams"
    const view = otherTeam ? otherTeam : as
    if (view) url = `/${scope.kind}s/${scope.key}/teams?as=${view}`
    return new Promise<AxiosResponse>((resolve, reject) => {
      get(pondURL(url)).then(resp => {
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  return (
    <TeamAPIContext.Provider
      value={{
        addTeam,
        getTeam,
        updateTeam,
        updatePreferences,
        listTeams,
        listObjectTeams,
        removeTeam,
        listAllTeams
      }}>
      {children}
    </TeamAPIContext.Provider>
  );
}

export const useTeamAPI = () => useContext(TeamAPIContext);
