import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import moment from "moment";
import { createContext, PropsWithChildren, useContext } from "react";
import PondProvider from "./pond/pond";
import { useAuth0 } from "@auth0/auth0-react";
import SnackbarProvider from "./Snackbar";

interface IHTTPContext {
  get: <T>(url: string, spreadOptions?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
  put: <T>(
    url: string,
    data?: any,
    spreadOptions?: AxiosRequestConfig
  ) => Promise<AxiosResponse<T>>;
  post: <T>(
    url: string,
    data?: any,
    spreadOptions?: AxiosRequestConfig
  ) => Promise<AxiosResponse<T>>;
  del: <T>(url: string, spreadOptions?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
  options: (demo?: boolean) => AxiosRequestConfig;
}

interface Props extends PropsWithChildren<any>{
  token: string;
}

export const HTTPContext = createContext<IHTTPContext>({} as IHTTPContext);

export default function HTTPProvider(props: Props) {
  const { children, token } = props;
  const { isAuthenticated, loginWithRedirect } = useAuth0();

  const defaultOptions = (demo: boolean = false) => {
    if (demo || !isAuthenticated || !token) {
      return {
        headers: {
          "Content-Type": "application/json"
        }
      };
    }

    const config = {
      headers: { 
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json"
      },
    };
    return config;
  };

  function isTokenExpired(token: string): boolean {
    try {
      // Split the token and decode the payload (second part)
      const payloadBase64 = token.split('.')[1];
      const decodedPayload = atob(payloadBase64); // Decode base64
      const payload = JSON.parse(decodedPayload);
  
      // Get expiration time (in seconds)
      const exp = payload.exp;
  
      if (!exp) return true; // No exp field? Treat as expired
  
      // Current time in seconds
      const now = Math.floor(Date.now() / 1000);
  
      // Compare
      return now >= exp;
    } catch (error) {
      console.error("Invalid token format:", error);
      return true; // Err on the side of caution if decoding fails
    }
  }

  function get<T>(url: string, spreadOptions?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    if (isTokenExpired(token)) loginWithRedirect()
    return axios.get(url, {...defaultOptions(), ...spreadOptions});
  }

  function put<T>(
    url: string,
    data?: any,
    spreadOptions?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    return axios.put(url, data, { ...defaultOptions(), ...spreadOptions });
  }

  function post<T>(
    url: string,
    data?: any,
    spreadOptions?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    return axios.post(url, data, { ...defaultOptions(), ...spreadOptions });
  }

  function del<T>(url: string, spreadOptions?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return axios.delete(url, { ...defaultOptions(), ...spreadOptions });
  }

  return (
    <HTTPContext.Provider
      value={{
        get,
        put,
        post,
        del,
        options: defaultOptions
      }}>
      {/* <BillingProvider> */}
        <PondProvider>
          <SnackbarProvider>
            {children}
          </SnackbarProvider>
          {/* <SecurityProvider> */}
            {/* <GitlabProvider>{children}</GitlabProvider> */}
          {/* </SecurityProvider> */}
        </PondProvider>
      {/* </BillingProvider> */}
    </HTTPContext.Provider>
  );
}

export const useHTTP = () => useContext(HTTPContext);

//returns a string depending on the given start and end to be used in a url query
export function dateRange(start: any, end: any): string {
  start = moment(start).toISOString();
  end = moment(end).toISOString();

  var queryRange = "";
  if (
    typeof start !== "undefined" &&
    start !== null &&
    typeof end !== "undefined" &&
    end !== null
  ) {
    queryRange = "?start=" + start + "&end=" + end;
  } else if (typeof start !== "undefined" && start !== null) {
    queryRange = "?start=" + start;
  } else if (typeof end !== "undefined" && end !== null) {
    queryRange += "?end=" + end;
  }

  return queryRange;
}
