// import { ApolloClient /*, createHttpLink */ } from '@apollo/client/core'
// import { ApolloClients } from '@vue/apollo-composable'
// import { boot } from 'quasar/wrappers'
// import { getClientOptions } from 'src/apollo'

// export default boot(
//   /* async */ ({ app }) => {
//     // Default client.
//     const options = /* await */ getClientOptions(/* {app, router ...} */)
//     const apolloClient = new ApolloClient(options)

//     // // Additional client `clientA`
//     // const optionsA = { ...options }
//     // // Modify options as needed.
//     // optionsA.link = createHttpLink({ uri: 'http://clientA.example.com' })
//     // const clientA = new ApolloClient(optionsA)

//     // // Additional client `clientB`
//     // const optionsB = { ...options }
//     // // Modify options as needed.
//     // optionsB.link = createHttpLink({ uri: 'http://clientB.example.com' })
//     // const clientB = new ApolloClient(optionsB)

//     const apolloClients: Record<string, ApolloClient<unknown>> = {
//       default: apolloClient,
//       // clientA,
//       // clientB,
//     }

//     app.provide(ApolloClients, apolloClients)
//   }
// )

///////
import { ApolloClient, createHttpLink } from '@apollo/client/core';
import { getMainDefinition } from '@apollo/client/utilities';
import { split } from '@apollo/client/core';
import { WebSocketLink } from '@apollo/link-ws';
import { onError } from '@apollo/client/link/error';

import { ApolloLink, concat, from } from 'apollo-link';

import { ApolloClients } from '@vue/apollo-composable';
import { boot } from 'quasar/wrappers';
import { LocalStorage } from 'quasar';
import { SessionStorage } from 'quasar';

import fetch from 'cross-fetch';

import { getClientOptions } from 'src/apollo';

import { getAPIurl } from '../utils';

let apollo = null;
let wsLink = null;
const urlFull = new URL(getAPIurl());
const url = `${urlFull.host}${urlFull.pathname}`;
const urlProtocol = urlFull.protocol;

const wsProtocol =
  urlProtocol === 'http:'
    ? 'ws://'
    : urlProtocol === 'https:'
    ? 'wss://'
    : null;

export default boot(({ app, ssrContext, store }) => {
  const headers = (addJwt = false) => {
    const obj = {
      'X-CSRFTOKEN':
        SessionStorage.getItem('csrf_token') ||
        LocalStorage.getItem('csrf_token') ||
        null,
      'X-AUTH-TOKEN':
        SessionStorage.getItem('auth_token') ||
        LocalStorage.getItem('auth_token') ||
        null,
    };
    const jwt =
      SessionStorage.getItem('jwt_token') ||
      LocalStorage.getItem('jwt_token') ||
      null;
    if (jwt != null && addJwt) {
      obj['Authorization'] = `JWT ${jwt}`;
    }
    return obj;
  };
  const options = getClientOptions(/* {app, router ...} */);

  // ****** клиент default ******
  const middlewareLink = new ApolloLink((operation, forward) => {
    operation.setContext({
      headers: headers(true),
    });
    return forward(operation);
  });

  const httpLink = createHttpLink({
    uri: `${urlProtocol}//${url}jwt/`,
    fetch: fetch,
    fetchOptions: {
      credentials: 'include',
      cache: 'no-cache',
    },
  });
  const errorLink = onError(({ graphQLErrors, networkError }) => {
    if (graphQLErrors)
      graphQLErrors.forEach(({ message, locations, path }) =>
        console.log(
          `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
        )
      );

    if (networkError) console.log(`[Network error]: ${networkError}`);
  });

  wsLink = process.env.CLIENT
    ? new WebSocketLink({
        uri: `${wsProtocol}${url}ws/`,
        webSocketProtocols: 'graphql-ws',
        options: {
          reconnect: true,
          // reconnectionAttempts: 10,
          // inactivityTimeout: 10 * 1000,
          lazy: true,
          connectionParams: () => {
            const jwt =
              LocalStorage.getItem('jwtToken') === 'null'
                ? null
                : LocalStorage.getItem('jwtToken');
            return jwt
              ? {
                  authorization: `JWT ${jwt}`,
                }
              : {};
          },
          connectionCallback: async (errors, result) => {
            // console.log('Result: ', result);
            if (errors) {
              console.log('Errors: ', errors);
            }
          },
        },
      })
    : null;

  const splitLink = process.env.CLIENT
    ? split(
        ({ query }) => {
          const definition = getMainDefinition(query);
          return (
            definition.kind === 'OperationDefinition' &&
            definition.operation === 'subscription'
          );
        },
        wsLink,
        httpLink
      )
    : httpLink;
  const clientDefault = new ApolloClient({
    ...options,
    link: concat(middlewareLink, from([errorLink, splitLink])),
  });

  clientDefault.onResetStore(async () => {
    // console.log('onreset');
    clientDefault.setLink(concat(middlewareLink, splitLink));
  });
  // ****** клиент default ******

  // ****** клиент registrado ******
  const middlewareLinkRegistrado = new ApolloLink((operation, forward) => {
    operation.setContext({
      headers: headers(),
    });
    return forward(operation);
  });

  const registradoLink = createHttpLink({
    uri: `${urlProtocol}//${url}registrado/`,
    fetch: fetch,
    fetchOptions: {
      credentials: 'include',
    },
  });
  const registradoErrorLink = onError(({ graphQLErrors, networkError }) => {
    if (graphQLErrors)
      graphQLErrors.forEach(({ message, locations, path }) =>
        console.log(
          `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
        )
      );

    if (networkError) console.log(`[Network error]: ${networkError}`);
  });

  const clientRegistrado = new ApolloClient({
    ...options,
    link: concat(
      middlewareLinkRegistrado,
      from([registradoErrorLink, registradoLink])
    ),
  });
  // ****** клиент registrado ******

  const apolloClients = {
    default: clientDefault,
    registrado: clientRegistrado,
  };
  apollo = apolloClients;
  app.provide(ApolloClients, apolloClients);
});
export { apollo, wsLink };
