import React from "react";
import { createClient, Provider } from "urql";
import { authExchange } from "@urql/exchange-auth";
import { makeOperation, fetchExchange } from "@urql/core";
import { config } from "../config";
import { GetTokenSilentlyOptions, useAuth0 } from "@auth0/auth0-react";

/**
 * Create urql authExchange instance that know how to get auth0 tokens
 */
const createAuthExchange = (
  getAccessTokenSilently: (
    options?: GetTokenSilentlyOptions | undefined
  ) => Promise<string>
) =>
  authExchange<{ token: string }>({
    addAuthToOperation: ({ authState, operation }) => {
      if (!authState || !authState.token) {
        return operation;
      }

      const fetchOptions =
        typeof operation.context.fetchOptions === "function"
          ? operation.context.fetchOptions()
          : operation.context.fetchOptions || {};

      return makeOperation(operation.kind, operation, {
        ...operation.context,
        fetchOptions: {
          ...fetchOptions,
          headers: {
            ...fetchOptions.headers,
            Authorization: `Bearer ${authState.token}`,
          },
        },
      });
    },
    getAuth: async ({ authState }) => {
      if (!authState) {
        const token = await getAccessTokenSilently();
        if (token) {
          return { token };
        }
        return null;
      }
      return null;
    },
    willAuthError: ({ authState }) => {
      //TODO: Actually check if JWT is expired ahead of time
      const isJWTExpired = () => false;
      if (!authState || isJWTExpired()) return true;
      return false;
    },
  });

export const GraphQLClientProvider: React.FC = ({ children }) => {
  const { getAccessTokenSilently } = useAuth0();
  const graphQLClient = createClient({
    url: `${config.rtiApiUrl}/graphql`,
    exchanges: [createAuthExchange(getAccessTokenSilently), fetchExchange],
  });

  return <Provider value={graphQLClient}>{children}</Provider>;
};
