import { ApolloClient, ApolloLink, InMemoryCache, split } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { HttpLink } from "@apollo/client/link/http"; //"apollo-link-http";
import { RetryLink } from "@apollo/client/link/retry";
import { WebSocketLink } from "@apollo/client/link/ws";
import { getMainDefinition } from "@apollo/client/utilities";
//import { split } from "apollo-link";
import apolloLogger from "apollo-link-logger";
//import axios from "axios";
import { auth } from "../firebase/firebase.utils";
import errorLink from "../graphql/apollo-error-handling";
//import { store } from "../redux/store";
const httpLink = new HttpLink({
  uri: process.env.REACT_APP_GRAPHQL_ENDPOINT,
});

const wsLink = new WebSocketLink({
  uri: process.env.REACT_APP_GRAPHQL_ENDPOINT_WS,
  options: {
    lazy: true,
    reconnect: true,
    connectionParams: async () => {
      const token = auth.currentUser && (await auth.currentUser.getIdToken());
      if (token) {
        return {
          headers: {
            authorization: token ? `Bearer ${token}` : "",
          },
        };
      }
    },
  },
});

const roundTripLink = new ApolloLink((operation, forward) => {
  // Called before operation is sent to server
  operation.setContext({ start: new Date() });

  return forward(operation).map((data) => {
    // Called after server responds
    const time = new Date() - operation.getContext().start;
    // console.log(
    //   `Operation ${operation.operationName} took ${time} to complete`
    // );
    TrackExecutionTime(operation.operationName, time);
    return data;
  });
});

const TrackExecutionTime = async (operationName, time) => {
  // if (process.env.NODE_ENV === "development") return;
  // const rdxStore = store.getState();
  // try {
  //   axios.post("/ioevent", {
  //     operationName,
  //     time,
  //     dbevent: true,
  //     user:
  //       rdxStore.user &&
  //       rdxStore.user.currentUser &&
  //       rdxStore.user.currentUser.email,
  //     imexshopid:
  //       rdxStore.user &&
  //       rdxStore.user.bodyshop &&
  //       rdxStore.user.bodyshop.imexshopid,
  //   });
  // } catch (error) {
  //   console.log("IOEvent Error", error);
  // }
};

const subscriptionMiddleware = {
  applyMiddleware: async (options, next) => {
    options.authToken =
      auth.currentUser && (await auth.currentUser.getIdToken());
    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 +
    //     "##",
    //   query
    // );
    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(
  roundTripLink.concat(
    retryLink.concat(errorLink.concat(authLink.concat(link)))
  )
);

const cache = new InMemoryCache({});

export default new ApolloClient({
  link: ApolloLink.from(middlewares),
  cache,
  connectToDevTools: process.env.NODE_ENV !== "production",
  defaultOptions: {
    watchQuery: {
      fetchPolicy: "network-only",
      nextFetchPolicy: "network-only",
      errorPolicy: "ignore",
    },
    query: {
      fetchPolicy: "network-only",
      errorPolicy: "all",
    },
    mutate: {
      errorPolicy: "all",
    },
  },
});
