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

export interface ListUsersResponse {
  users: User[];
  nextOffset: number;
  total: number;
}
export interface IUserAPIContext {
  listUsers: (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    by?: string,
    search?: string
  ) => Promise<ListUsersResponse>;
  listProfiles: () => Promise<pond.UserProfile[]>;
  listObjectUsers: (scope: Scope) => Promise<any>;
  updateObjectUsers: (scope: Scope, users: pond.IUser[]) => Promise<any>;
  getUser: (id: string, scope?: Scope) => Promise<User>;
  getUserWithTeam: (
    id: string,
    team?: string,
    scope?: any
  ) => Promise<AxiosResponse<pond.GetUserWithTeamResponse>>;
  getProfile: (id: string) => Promise<pond.UserProfile>;
  // getUsers: (ids: string[]) => Promise<User[]>;
  // getProfiles: (ids: string[]) => Promise<pond.UserProfile[]>;
  // getUserSettings: (userID: string) => Promise<any>;
  // updateUserSettings: (userID: string, body: pond.IUserSettings) => Promise<any>;
  // updateUserStatus: (userID: string, body: pond.IUserStatus) => Promise<any>;
  updateUser: (id: string, body: pond.User) => Promise<any>;
  // getUserObjectHistory: (
  //   id: string,
  //   objects: number[],
  //   start: string,
  //   end: string
  // ) => Promise<AxiosResponse<pond.GetUserObjectHistoriesResponse>>;
}

export const UserAPIContext = createContext<IUserAPIContext>({} as IUserAPIContext);

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

  const listUsers = (
    limit: number,
    offset: number,
    order?: "asc" | "desc",
    by?: string,
    search?: string
  ): Promise<ListUsersResponse> => {
    return new Promise((resolve, reject) => {
      get(
        pondURL(
          "/users?limit=" +
            limit +
            "&offset=" +
            offset +
            ("&order=" + (order ? order : "asc")) +
            ("&by=" + (by ? by : "name")) +
            (search ? "&search=" + search : "")
        )
      )
        .then((res: any) => {
          let users: User[] = [];
          if (res && res.data && res.data.users) {
            res.data.users.forEach((raw: any) => users.push(User.any(raw)));
          }
          resolve({
            users: users,
            nextOffset: or(res.data.nextOffset, 0),
            total: or(res.data.total, 0)
          });
        })
        .catch((err: any) => reject(err));
    });
  };

  const listProfiles = (): Promise<pond.UserProfile[]> => {
    return new Promise((resolve, reject) => {
      get(pondURL("/profiles/"))
        .then((res: any) => {
          let profiles: pond.UserProfile[] = [];
          if (res && res.data && res.data.users) {
            res.data.users.forEach((raw: any) => profiles.push(pond.UserProfile.fromObject(raw)));
          }
          resolve(profiles);
        })
        .catch((err: any) => reject(err));
    });
  };

  const listObjectUsers = (scope: Scope) => {
    let sql = "/" + scope.kind + "s/" + scope.key + "/users";
    if (as) sql = sql + "?as=" + as;
    return get(pondURL(sql));
  };

  const updateObjectUsers = (scope: Scope, users: pond.IUser[]) => {
    return put(pondURL("/users" + objectQueryParams(scope)), { users });
  };

  // const getUser = (id: string): Promise<User> => {
  const getUser = (id: string, scope?: Scope): Promise<any> => {
    let partial = "/users/" + id;
    if (scope) partial += "?kind=" + scope.kind + "&key=" + scope.key;
    return new Promise(function(resolve, reject) {
      get(pondURL(partial))
        .then((response: any) => {
          let data = response.data
          if (Array.isArray(data.permissions)) {
            data.permissions = data.permissions.map((perm: unknown) => {
              const mappedPerm = pond.Permission[perm as keyof typeof pond.Permission];
              return mappedPerm !== undefined ? mappedPerm : null; // Return null for invalid keys
            }).filter(Boolean); // Optionally filter out any null values
          } else {
            console.error("data.permissions is not an array or does not exist");
            data.permissions = [];
          }
          
          // data.permissions = data.permissions.map((perm: unknown) => pond.Permission[perm as unknown as keyof typeof pond.Permission]);
          resolve(data)
        })
        .catch((error: any) => reject(error));
    });
  };

  const getUserWithTeam = (
    id: string,
    team?: string,
    scope?: any
  ): Promise<AxiosResponse<pond.GetUserWithTeamResponse>> => {
    let partial = "/userWithTeam/" + id;
    if (scope) partial += "?kind=" + scope.kind + "&key=" + scope.key;
    if (team) {
      if (partial.includes("?")) {
        partial += "&team=" + team;
      } else {
        partial += "?team=" + team;
      }
    }
    return new Promise(function(resolve, reject) {
      get(pondURL(partial))
        .then((response: any) => resolve(response))
        .catch((error: any) => reject(error));
    });
  };

  const getProfile = (id: string): Promise<pond.UserProfile> => {
    return new Promise((resolve, reject) => {
      get(pondURL("/profiles/" + id))
        .then((res: any) => resolve(pond.UserProfile.fromObject(res.data)))
        .catch((err: any) => reject(err));
    });
  };

  // const getUsers = (ids: string[]): Promise<User[]> => {
  //   return new Promise((resolve, reject) => {
  //     get(pondURL("/users/?ids=" + ids.join(",")))
  //       .then((res: any) => {
  //         let users: User[] = [];
  //         if (res && res.data && res.data.users) {
  //           users = res.data.users.map((data: any) => User.any(data));
  //         }
  //         resolve(users);
  //       })
  //       .catch((err: any) => reject(err));
  //   });
  // };

  // const getProfiles = (ids: string[]): Promise<pond.UserProfile[]> => {
  //   return new Promise((resolve, reject) => {
  //     get(pondURL("/profiles/?ids=" + ids.join(",")))
  //       .then((res: any) => {
  //         let profiles: pond.UserProfile[] = [];
  //         if (res && res.data && res.data.users) {
  //           profiles = res.data.users.map((raw: any) => pond.UserProfile.fromObject(raw));
  //         }
  //         resolve(profiles);
  //       })
  //       .catch((err: any) => reject(err));
  //   });
  // };

  // const getUserSettings = (userID: string) => {
  //   return get(pondURL("/users/" + userID + "/settings"));
  // };

  // const updateUserSettings = (userID: string, body: pond.IUserSettings) => {
  //   return put(pondURL("/users/" + userID + "/settings"), body);
  // };

  // const updateUserStatus = (userID: string, body: pond.IUserStatus) => {
  //   return put(pondURL("/users/" + userID + "/status"), body);
  // };

  const updateUser = (id: string, body: pond.User) => {
    return put(pondURL("/users/" + id), body);
  };

  // const getUserObjectHistory = (id: string, objects: number[], start: string, end: string) => {
  //   return get<pond.GetUserObjectHistoriesResponse>(
  //     pondURL(
  //       "/users/" +
  //         id +
  //         "/objectHistories/?objects=" +
  //         objects.toString() +
  //         "&start=" +
  //         start +
  //         "&end=" +
  //         end
  //     )
  //   );
  // };

  return (
    <UserAPIContext.Provider
      value={{
        listUsers,
        listProfiles,
        listObjectUsers,
        updateObjectUsers,
        getUser,
        getUserWithTeam,
        getProfile,
        // getUsers,
        // getProfiles,
        // getUserSettings,
        // updateUserSettings,
        // updateUserStatus,
        updateUser,
        // getUserObjectHistory
      }}>
      {children}
    </UserAPIContext.Provider>
  );
}

export const useUserAPI = () => useContext(UserAPIContext);
