//GQL Imports
import {
  ApolloClient,
  from,
  HttpLink,
  InMemoryCache,
  split,
} from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { onError } from "@apollo/client/link/error";
import { RetryLink } from "@apollo/client/link/retry";
import { WebSocketLink } from "@apollo/client/link/ws";
import { getMainDefinition } from "@apollo/client/utilities";
import { auth } from "../firebase/firebase.utils";
import env from "../env";
const httpLink = new HttpLink({
  // uri: "https://bodyshop-dev-db.herokuapp.com/v1/graphql",
  uri: env.uri,
});

const wsLink = new WebSocketLink({
  //uri: "wss://bodyshop-dev-db.herokuapp.com/v1/graphql",
  uri: "wss://db.imex.online/v1/graphql",
  options: {
    lazy: true,
    reconnect: true,
    connectionParams: async () => {
      const token =
        auth.currentUser && (await auth.currentUser.getIdToken(true));
      if (token) {
        return {
          headers: {
            authorization: token ? `Bearer ${token}` : "",
          },
        };
      }
    },
  },
});

//https://stackoverflow.com/questions/57163454/refreshing-a-token-with-apollo-client-firebase-auth

const errorLink = onError(
  ({ graphQLErrors, networkError, operation, forward }) => {
    console.error(graphQLErrors);
    if (graphQLErrors)
      graphQLErrors.forEach(({ message, locations, path }) =>
        console.error(
          `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
        )
      );
    if (networkError)
      console.error(`[Network error]: ${JSON.stringify(networkError)}`);
  }
);

const subscriptionMiddleware = {
  applyMiddleware: async (options, next) => {
    options.authToken =
      auth.currentUser && (await auth.currentUser.getIdToken(true));
    next();
  },
};
wsLink.subscriptionClient.use([subscriptionMiddleware]);

const link = split(
  // split based on operation type
  ({ query }) => {
    const definition = getMainDefinition(query);
    // console.log(
    //   "##Intercepted GQL Transaction : " +
    //     definition.operation +
    //     "|" +
    //     //   definition.name.value +
    //     "##"
    // );
    return (
      definition.kind === "OperationDefinition" &&
      definition.operation === "subscription"
    );
  },
  wsLink,
  httpLink
);

const authLink = setContext((_, { headers }) => {
  return (
    auth.currentUser &&
    auth.currentUser.getIdToken().then((token) => {
      if (token) {
        return {
          headers: {
            ...headers,
            authorization: token ? `Bearer ${token}` : "",
          },
        };
      } else {
        return { headers };
      }
    })
  );
});

const retryLink = new RetryLink({
  delay: {
    initial: 500,
    max: 5,
    jitter: true,
  },
  attempts: {
    max: 5,
    retryIf: (error, _operation) => !!error,
  },
});

// const middlewares = [];
// if (process.env.NODE_ENV === "development") {
//   middlewares.push(apolloLogger);
// }

// middlewares.push(retryLink.concat(errorLink.concat(authLink.concat(link))));

const cache = new InMemoryCache({});

export const client = new ApolloClient({
  //link: ApolloLink.from(middlewares),
  //link: from([apolloLogger, errorLink, authLink, link]),
  link: from([authLink, link]),
  cache,
  notifyOnNetworkStatusChange: true,

  //   connectToDevTools: process.env.NODE_ENV !== "production",
  defaultOptions: {
    watchQuery: {
      fetchPolicy: "network-only",
      nextFetchPolicy: "network-only",
    },
    query: {
      fetchPolicy: "network-only",
    },
  },
});
