/* global alert */
import { reduxForm } from 'redux-form';
import { compose } from 'redux';
import { AccessToken } from 'react-native-fbsdk';
import { AsyncStorage } from 'react-native';
import { graphql, gql, withApollo } from 'react-apollo';
import axios from 'axios';
import { withState } from 'recompose';
import LoginForm from '../../components/LoginForm';

const AUTH0_URL = 'https://rafa93br.auth0.com/oauth/access_token';
const AUTH0_CLIENT_ID = 'Bdte7rvlXysilkTWYhmv5sTCvSAJ2zzx';

/**
 * Form validation
 */
const validate = values => null;

const signinUserMutation = gql`
  mutation($email:String!, $password: String!) {
    signinUser(input: {
      email: {
        email: $email,
        password: $password,
      },
      clientMutationId: "123",
    }){
      token
      viewer {
        user {
          id
          email
          picture
          name
        }
      }
    }
  }
`;

const createUserWithAuth0Mutation = gql`
  mutation createUser($name: String, $picture: String, $idToken: String!) {
    createUser(input: {
      name: $name,
      picture: $picture,
      authProvider: {
        auth0: {
          idToken: $idToken,
        },
      },
      clientMutationId: "123",
    }) {
      user {
        id
        name
        picture
      }
      clientMutationId
    }
}`;


const getFacebookInfo = accessToken => axios.get('https://graph.facebook.com/v2.9/me', {
  params: {
    access_token: accessToken,
    fields: 'picture.type(large){url,width,height,is_silhouette},email,name,id',
  },
});

const getAuth0Info = (url, clientId, accessToken) => axios.post(url, {
  client_id: clientId,
  access_token: accessToken,
  connection: 'facebook',
  scope: 'openid',
});


const updateLocalStore = (proxy, mutationResult) => {
  if (mutationResult &&
    mutationResult.data &&
    mutationResult.data.signinUser &&
    mutationResult.data.signinUser.viewer &&
    mutationResult.data.signinUser.viewer.user) {
    const query = gql`
    query {
      viewer {
        user {
          id
          email
        }
      }
    }
    `;

    proxy.writeQuery({
      query,
      data: mutationResult.data.signinUser,
    });
  }
};

export default compose(
  /**
   * Get access to client object to call client.resetStore
   */
  withApollo,
  /**
   * State
   */
  withState('loading', 'setLoading', false),
  /**
   * Auth0 Authentication
   */
  graphql(createUserWithAuth0Mutation, ({
    props: ({ ownProps: { client, setLoading }, mutate }) => ({
      loginWithFacebook: async (error, result) => {
        if (error) {
          alert(`login has error: ${result.error}`);
          return;
        }
        if (result.isCancelled) {
          alert('login is cancelled.');
          return;
        }

        setLoading(true);
        try {
          const accessTokenData = await AccessToken.getCurrentAccessToken();
          const accessToken = accessTokenData.accessToken.toString();
          const auth0Response = await getAuth0Info(AUTH0_URL, AUTH0_CLIENT_ID, accessToken);
          const idToken = auth0Response.data.id_token;
          const fbResponse = await getFacebookInfo(accessToken);
          const picture = fbResponse.data.picture.data.url;
          const name = fbResponse.data.name;
          const email = fbResponse.data.email;  // TODO: contact email
          AsyncStorage.setItem('token', idToken);

          try {
            await mutate({
              variables: {
                name,
                picture,
                idToken,
              },
            });
          } catch (err) {
            console.log(err);
          }
        } catch (err) {
          setLoading(false);
          alert(err.toString());
        } finally {
          client.resetStore();
        }
      },
    }),
  })),
  /**
   * E-mail Authentication
   */
  graphql(signinUserMutation, {
    props: ({ ownProps: { setLoading }, mutate }) => ({
      loginWithEmail: async ({ email, password }) => {
        setLoading(true);

        try {
          /**
           * Sign in with given email and password
           */
          const response = await mutate({
            variables: {
              email,
              password,
            },
            /**
             * On success, update the local Apollo store to update the UI and draw MainNavigation
             */
            update: updateLocalStore,
          });
          /**
           * Write obtained token to local STORAGE
           */
          const token = response.data.signinUser.token;
          if (token) {
            AsyncStorage.setItem('token', token);
          } else {
            throw new Error('No token on response');
          }
        } catch (err) {
          setLoading(false);
          alert(err.toString());
        }
      },
    }),
  }),
  /**
   * Form
   */
  reduxForm({
    form: 'login',
    validate,
  }),
)(LoginForm);