import React, { Component } from "react";

import App from "./App";
import Spin from "../components/loading-spinner/loading-spinner.component";

import ApolloClient from "apollo-client";
import { split } from "apollo-link";
import { HttpLink } from "apollo-link-http";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";
import { InMemoryCache } from "apollo-cache-inmemory";
import { setContext } from "apollo-link-context";
import { resolvers, typeDefs } from "../graphql/resolvers";
import apolloLogger from "apollo-link-logger";
import { ApolloLink } from "apollo-boost";
import { ApolloProvider } from "react-apollo";
import { persistCache } from "apollo-cache-persist";
import initialState from "../graphql/initial-state";
import { shouldRefreshToken, refreshToken } from "../graphql/middleware";
import errorLink from "../graphql/apollo-error-handling";

class AppContainer extends Component {
  state = {
    client: null,
    loaded: false
  };
  async componentDidMount() {
    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: () => {
          const token = localStorage.getItem("token");
          if (token) {
            return {
              headers: {
                authorization: token ? `Bearer ${token}` : ""
              }
            };
          }
        }
      }
    });

    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 }) => {
      // get the authentication token from local storage if it exists
      const token = localStorage.getItem("token");
      // return the headers to the context so httpLink can read them
      if (token) {
        // if (shouldRefreshToken) {
        //   refreshToken();
        // }

        return {
          headers: {
            ...headers,
            authorization: token ? `Bearer ${token}` : ""
          }
        };
      } else {
        return { headers };
      }
    });

    const middlewares = [];
    if (process.env.NODE_ENV === "development") {
      middlewares.push(apolloLogger);
    }
    middlewares.push(errorLink.concat(authLink.concat(link)));

    const cache = new InMemoryCache();

    const client = new ApolloClient({
      link: ApolloLink.from(middlewares),
      cache,
      typeDefs,
      resolvers,
      connectToDevTools: true
    });

    client.writeData({
      data: initialState
    });

    try {
      // See above for additional options, including other storage providers.
      await persistCache({
        cache,
        storage: window.sessionStorage,
        debug: true
      });
    } catch (error) {
      console.error("Error restoring Apollo cache", error);
    }

    this.setState({
      client,
      loaded: true
    });

    //Init local state.
  }

  render() {
    const { client, loaded } = this.state;

    if (!loaded) {
      return <Spin />;
    }

    return (
      <ApolloProvider client={client}>
        <App />
      </ApolloProvider>
    );
  }
}

export default AppContainer;
