import { useHTTP } from "../http";
import { usePermissionAPI } from "./permissionAPI";
import { createContext, PropsWithChildren, useContext } from "react";
import { pond } from "protobuf-ts/pond";
import { or } from "utils/types";
import { User, groupScope } from "models";
import { pondURL } from "./pond";
import { AxiosResponse } from "axios";
import { useGlobalState } from "../StateContainer";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";

export interface IGroupAPIContext {
  addGroup: (group: pond.GroupSettings) => Promise<any>;
  addDevice: (group: number, device: number) => Promise<any>;
  removeDevice: (group: number, device: number) => Promise<any>;
  updateGroup: (id: number, group: pond.GroupSettings) => Promise<any>;
  removeGroup: (id: number) => Promise<any>;
  getGroup: (id: number) => Promise<any>;
  getGroupAndPermissions: (id: number) => Promise<AxiosResponse<pond.GetGroupAndPermissionsResponse>>;
  getGroupPermissions: (
    id: number,
    keys?: string[],
    types?: string[],
  ) => Promise<AxiosResponse<pond.GetPermissionsResponse>>;
  listGroups: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    keys?: string[],
    types?: string[],
  ) => Promise<AxiosResponse<pond.ListGroupsResponse>>;
  listGroupDevices: (
    id: number,
    limit: number,
    offset: number,
    order: "asc" | "desc",
    search?: string,
    comprehensive?: boolean
  ) => Promise<AxiosResponse<pond.GetMultiDeviceResponse>>;
  updateGroupPermissions: (id: number, users: User[]) => Promise<any>;
}

function buildQueryString(params: Record<string, string | string[] | number | null | undefined>): string {
  // Filter out null, undefined, or empty string values
  const validParams = Object.entries(params)
      .filter(([_, value]) => value != null && value !== '')
      .map(([key, value]) => `${key}=${value}`);

  if (validParams.length === 0) {
      return '';
  }

  // Join parameters with '&' and prepend '?'
  return `?${validParams.join('&')}`;
}

export const GroupAPIContext = createContext<IGroupAPIContext>({} as IGroupAPIContext);

interface Props {}

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

  const addGroup = (group: pond.GroupSettings) => {
    // let url = pondURL("/groups")
    // let keys = getContextKeys()
    // let types = getContextTypes()
    // if (as) url = pondURL("/groups?as=" + as)
    const params = {
      keys: getContextKeys(),
      types: getContextTypes(),
      as: getContextTypes().includes("team") ? undefined : as
    }
    let url = pondURL(`/groups${buildQueryString(params)}`)
    return new Promise<AxiosResponse>((resolve, reject) => {
      post(url, group).then(resp => {
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const addDevice = (group: number, device: number) => {
    let url = "/groups/" + group + "/devices/" + device + "/add";
    if (as) url = url + "?as=" + as
    return new Promise<AxiosResponse>((resolve, reject) => {
      post(pondURL(url), group).then(resp => {
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const removeDevice = (group: number, device: number) => {
    let url = "/groups/" + group + "/devices/" + device + "/remove";
    if (as) url = url  + "?as=" + as
    return new Promise<AxiosResponse>((resolve, reject) => {
      post(pondURL(url), group).then(resp => {
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const updateGroup = (id: number, group: pond.GroupSettings) => {
    let url = pondURL("/groups/" + id)
    if (as) url = pondURL("/groups/" + id + "?as=" + as)
    return new Promise<AxiosResponse>((resolve, reject) => {
      put(url, group).then(resp => {
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const removeGroup = (id: number) => {
    const params = {
      keys: getContextKeys(),
      types: getContextTypes(),
      as: getContextTypes().includes("team") ? undefined : as
    }
    pondURL(`/groups/${id}${buildQueryString(params)}`)
    return new Promise<AxiosResponse>((resolve, reject) => {
      del(pondURL(`/groups/${id}${buildQueryString(params)}`)).then(resp => {
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const getGroup = (id: number) => {
    let url = pondURL("/groups/" + id)
    if (as) return get(pondURL("/groups/" + id + "?as=" + as));
    return new Promise<AxiosResponse>((resolve, reject) => {
      get(url).then(resp => {
        resolve(resp)
      }).catch(err => {
        reject(err)
      })
    })
  };

  const getGroupAndPermissions = (
    id: number,
    keys?: string[],
    types?: string[],
  ) => {
    keys = keys ? keys : getContextKeys();
    types = types? types : getContextTypes();
    let url = "/groupAndPermissions/" + id
    if (as) {
      url = url + "?as=" + as +
      +
      (keys ? "?keys=" + keys.toString() : "") +
      (types ? "&types=" + types.toString() : "")
    } else {
      url = url + 
        (keys ? "?keys=" + keys.toString() : "") +
        (types ? "&types=" + types.toString() : "")
    }
    return new Promise<AxiosResponse<pond.GetGroupAndPermissionsResponse>>((resolve, reject) => {
      get<pond.GetGroupAndPermissionsResponse>(pondURL(url)).then(resp => {
        resp.data = pond.GetGroupAndPermissionsResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const getGroupPermissions = (
    id: number,
    keys?: string[],
    types?: string[],
  ) => {
    // keys = keys ? keys : getContextKeys();
    // types = types? types : getContextTypes();
    // let url = "/groupPermissions/" + id
    // if (as) {
    //   url = url + "?as=" + as +
    //   +
    //   (keys ? "?keys=" + keys.toString() : "") +
    //   (types ? "&types=" + types.toString() : "")
    // } else {
    //   url = url + 
    //     (keys ? "?keys=" + keys.toString() : "") +
    //     (types ? "&types=" + types.toString() : "")
    // }
    const params = {
      keys: getContextKeys(),
      types: getContextTypes(),
      as: getContextTypes().includes("team") ? undefined : as,
    }
    let url = `/groupPermissions/${id}${buildQueryString(params)}`
    return new Promise<AxiosResponse<pond.GetPermissionsResponse>>((resolve, reject) => {
      get<pond.GetPermissionsResponse>(pondURL(url)).then(resp => {
        resp.data = pond.GetPermissionsResponse.fromObject(resp.data)
        return resolve(resp);
      }).catch(err => {
        return reject(err)
      })
    })
    // return get<pond.GetPermissionsResponse>(pondURL(url));
  };

  const listGroups = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    orderBy?: string,
    search?: string,
    asRoot?: boolean,
    keys?: string[],
    types?: string[]
  ) => {
    keys = keys ? keys : getContextKeys();
    types = types? types : getContextTypes();
    types.forEach((type, index) => {
      if (type === "group") {
        types && types.splice(index, 1)
        keys && keys.splice(index, 1)
      }
    })
    let url = pondURL(
      "/groups" +
        "?limit=" +
        limit +
        "&offset=" +
        offset +
        ("&order=" + or(order, "asc")) +
        ("&orderBy=" + or(orderBy, "id")) +
        (search ? "&search=" + search : "") +
        (asRoot ? "&asRoot=" + asRoot.toString() : "") +
        (as ? "&as=" + as.toString() : "") + 
        (keys.length > 0 ? "&keys=" + keys : "") +
        (types.length > 0 ? "&types=" + types : "") 
    )
    return new Promise<AxiosResponse<pond.ListGroupsResponse>>((resolve, reject) => {
      get<pond.ListGroupsResponse>(url).then(resp => {
        resp.data = pond.ListGroupsResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const listGroupDevices = (
    id: number,
    limit: number,
    offset: number,
    order: "asc" | "desc",
    search?: string,
    comprehensive: boolean = false
  ) => {
    let url =       pondURL(
      "/groups/" +
        id +
        "/devices?limit=" +
        limit +
        "&offset=" +
        offset +
        "&order=" +
        order +
        (search ? "&search=" + search : "") +
        (comprehensive ? "&comprehensive=" + comprehensive.toString() : "") +
        (as ? "&as=" + as.toString() : "")
    )
    return new Promise<AxiosResponse<pond.GetMultiDeviceResponse>>((resolve, reject) => {
      get<pond.GetMultiDeviceResponse>(url).then(resp => {
        resp.data = pond.GetMultiDeviceResponse.fromObject(resp.data)
        return resolve(resp)
      }).catch(err => {
        return reject(err)
      })
    })
  };

  const updateGroupPermissions = (id: number, users: User[]) => {
    return permissionAPI.updatePermissions(groupScope(id.toString()), users);
  };

  return (
    <GroupAPIContext.Provider
      value={{
        addGroup,
        addDevice,
        removeDevice,
        updateGroup,
        removeGroup,
        getGroup,
        getGroupPermissions,
        getGroupAndPermissions,
        listGroups,
        listGroupDevices,
        updateGroupPermissions
      }}>
      {children}
    </GroupAPIContext.Provider>
  );
}

export const useGroupAPI = () => useContext(GroupAPIContext);
