import ApolloClient from 'apollo-client';
import {ApolloLink, Observable} from 'apollo-link';
import {InMemoryCache} from 'apollo-cache-inmemory';
import {createHttpLink} from 'apollo-link-http';
import {onError} from 'apollo-link-error';
import {displayError, setFlash} from '../actions';
import {push} from 'react-router-redux';
import queryString from 'query-string';
import {BOARD} from './board';

let dispatch = null;

const SERVERS = {
  production: 'https://api.wandb.ai/quiver',
  // development: 'http://gql.test/graphql',
  development: 'http://gql.test/quiver',
  devprod: 'https://api.wandb.ai/quiver',
  board:
    process.env.NODE_ENV === 'production'
      ? 'http://localhost:7177/graphql'
      : '/graphql',
};
export const SERVER =
  process.env.REACT_APP_BACKEND_URL ||
  SERVERS[process.env.REACT_APP_SERVER || process.env.NODE_ENV];
const httpLink = createHttpLink({uri: SERVER});

const authMiddleware = new ApolloLink((operation, forward) => {
  if (BOARD) return forward(operation);
  let qs = queryString.parse(document.location.search);
  let token = qs.token || localStorage.getItem('id_token');

  if (token) {
    operation.setContext(({headers = {}}) => ({
      headers: {
        ...headers,
        authorization: `Bearer ${token}`,
      },
    }));
  }

  return forward(operation);
});

const stackdriverMiddleware = new ApolloLink((operation, forward) => {
  let qs = queryString.parse(document.location.search);

  if (qs.trace) {
    console.log('DOING TRACE');
    let count = parseInt(localStorage.getItem('request_count'), 10);
    operation.setContext(({headers = {}}) => ({
      headers: {
        ...headers,
        'X-Cloud-Trace-Context':
          localStorage.getItem('page_id') + '/' + count + ';o=1',
      },
    }));
    localStorage.setItem('request_count', count + 1);
  }

  return forward(operation);
});

const userTimingMiddleware = new ApolloLink((operation, forward) => {
  const uuid = localStorage.getItem('page_id');
  return forward(operation).map(data => {
    if (window.performance && !BOARD) {
      setTimeout(() => {
        try {
          window.performance.mark(uuid + '-end');
          window.performance.measure(
            operation.operationName,
            uuid + '-start',
            uuid + '-end',
          );
          const measure = window.performance.getEntriesByName(
            operation.operationName,
          )[0];
          window.ga(
            'send',
            'timing',
            operation.operationName,
            measure.duration,
          );
        } catch (e) {
          console.warn('unable to time pageview', e);
        }
      });
    }
    return data;
  });
});

const errorLink = onError(({networkError, graphQLErrors}, store) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(error => {
      let {message, code} = error;
      if (code === 401) {
        localStorage.removeItem('id_token');
        if (document.location.pathname !== '/login') {
          localStorage.setItem('redirect', document.location.pathname);
        }
        dispatch(push('/login'));
      } else {
        console.error(`GraphQL error ${message} (${code}):`);
        dispatch(displayError(error));
      }
    });
  }
  if (networkError) {
    console.error(`Network Error: ${networkError}`);
    if (networkError.result) {
      console.error(networkError.result.errors);
    }

    dispatch(setFlash({message: 'Backend Unavailable', color: 'red'}));
  }
});

const link = ApolloLink.from([
  authMiddleware,
  stackdriverMiddleware,
  userTimingMiddleware,
  errorLink,
  httpLink,
]);

const apolloClient = new ApolloClient({
  link: link,
  cache: new InMemoryCache({
    dataIdFromObject: object => object.id,
  }),
});

export const connectStoreToApollo = store => {
  dispatch = store.dispatch;
};

export default apolloClient;

@@ -1002,16 +1002,155 @@
 ation);%0A
+  return new Observable(observable =%3E %7B%0A    let sub = null;%0A    this.c._auth.jwt().then(t =%3E %7B%0A      //The signup flow accepts a token%0A    
   let qs
@@ -1197,16 +1197,20 @@
 earch);%0A
+    
   let to
@@ -1231,43 +1231,16 @@
  %7C%7C 
-localStorage.getItem('id_token');%0A%0A
+t;%0A%0A    
   if
@@ -1246,24 +1246,28 @@
 f (token) %7B%0A
+    
     operatio
@@ -1294,32 +1294,36 @@
 rs = %7B%7D%7D) =%3E (%7B%0A
+    
       headers: %7B
@@ -1323,32 +1323,36 @@
 ders: %7B%0A        
+    
 ...headers,%0A    
@@ -1339,32 +1339,36 @@
     ...headers,%0A
+    
         authoriz
@@ -1391,35 +1391,43 @@
 %7Btoken%7D%60,%0A      
+   
+ 
 %7D,%0A
+    
     %7D));%0A  %7D%0A%0A  
@@ -1419,29 +1419,36 @@
    %7D));%0A
+    
   %7D%0A%0A  
-return
+    sub =
  forward
@@ -1450,32 +1450,162 @@
 rward(operation)
+.subscribe(observable);%0A    %7D);%0A    //TODO: I think this is always null...%0A    return () =%3E (sub ? sub.unsubscribe() : null);%0A  %7D)
 ;%0A%7D);%0A%0Aconst sta

Revert "Revert "Fix token refresh"."