import fetch from 'isomorphic-fetch';
import forEach from 'lodash/forEach';
import map from 'lodash/map';
import { routeActions } from 'redux-simple-router';
import { getAuthKey, setAuthKey,
         deleteSavedLayout, deleteAuthKey,
         handleAPIResponse
} from 'utils/session';
import { userService } from 'services/';

export const LOG_IN_USER = 'LOG_IN_USER';
function loginUser() {
  return {
    type: LOG_IN_USER
  };
}

export const USER_LOGGED_IN = 'USER_LOGGED_IN';
function loggedIn(json) {
  return {
    type: USER_LOGGED_IN,
    user: json.User,
    key: json.Key,
    permissions: json.Permissions,
  };
}

export const LOG_OUT_USER = 'LOG_OUT_USER';
function logoutUser() {
  return {
    type: LOG_OUT_USER
  };
}

export const USER_LOGGED_OUT = 'USER_LOGGED_OUT';
function loggedOut() {
  return {
    type: USER_LOGGED_OUT
  };
}

export const USER_NOT_LOGGED_IN = 'USER_NOT_LOGGED_IN';
function notLoggedIn() {
  return {
    type: USER_NOT_LOGGED_IN
  };
}

export const REGISTER_USER = 'REGISTER_USER';
function registerUser() {
  return {
    type: REGISTER_USER
  };
}

export const UPDATE_USER = 'UPDATE_USER';
function updateUser() {
  return {
    type: UPDATE_USER
  };
}

export const CANCEL_UPDATE = 'CANCEL_UPDATE';
export function cancelUpdate() {
  return {
    type: CANCEL_UPDATE
  };
}

export const REQUEST_SESSION = 'REQUEST_SESSION';
function requestSession() {
  return {
    type: REQUEST_SESSION
  };
}

export const RECEIVE_SESSION = 'RECEIVE_SESSION';
function receiveSession(json) {
  return {
    type: RECEIVE_SESSION,
    user: json.User,
    key: json.Key,
    permissions: json.Permissions,
  };
}

export const LOGIN_ERROR = 'LOGIN_ERROR';
function loginError(error) {
  return {
    type: LOGIN_ERROR,
    error
  };
}

export const REGISTER_ERROR = 'REGISTER_ERROR';
function registerError(error) {
  return {
    type: REGISTER_ERROR,
    error
  };
}

export const UPDATE_ERROR = 'UPDATE_ERROR';
function updateError(error) {
  return {
    type: UPDATE_ERROR,
    error
  };
}

export function login(username, password) {
  return dispatch => {
    dispatch(loginUser());

    return fetch(`${process.env.PRO_API}/user/login/`, {
      headers: {'accept': 'application/json', 'content-type': 'application/json'},
      body: JSON.stringify({username, password}),
      method: 'post'
    })
    .then(handleAPIResponse)
    .then(json => {
      setAuthKey(json);

      dispatch(loggedIn(json));

      // HACK: temporarily makes watchlists work.
      userService.getWatchlists();

      const user = json.User;
      const permissions = json.Permissions;

      bzTrack.identify(user.uid, {
        name: user.firstname + ' ' + user.lastname,
        email: user.email,
        phone: user.phone,
        username: user.username
      });

      // Olark
      olarkUpdateNickname(user.username);

      if (user.firstname === '' || user.lastname === '') {
        olarkUpdateFullName(user.username);
      } else {
        olarkUpdateFullName(user.firstname + ' ' + user.lastname);
      }

      olarkUpdateEmailAddress(user.email);
      olarkUpdatePhoneNumber(user.phone);

      if (permissions !== undefined) {
        // setup olark chat if they have permissions
        for (const permission of permissions) {
          if (permission === 'can_access_deskchat') {
            olarkShow();
            break;
          }
        }
      }

      // Sentry
      sentryUser(user.uid, user.email);
    })
    .catch(error => {
      dispatch(loginError(error));
    });
  };
}

export function logout() {
  return dispatch => {
    dispatch(logoutUser());

    // Remove auth keys and saved layouts
    deleteAuthKey();
    deleteSavedLayout();

    // Dispatch our final props/state change
    dispatch(loggedOut());

    // log out the user
    bzTrack.logout();
  };
}

export function register(email, password) {
  return dispatch => {
    dispatch(registerUser());

    const data = {
      email: email,
      password: password,
      username: email,
      auth_type: 'key',
      device_name: 1,
      device_type: 'desktop',
      device_uid: 1
    };

    return fetch(`${process.env.SERVICES_ROOT}/services/user/register`, {
      headers: {'accept': 'application/json', 'content-type': 'application/json'},
      body: JSON.stringify(data),
      method: 'post'
    })
    .then(handleAPIResponse)
    .then(json => {
      // Registered, log them in
      // for UI purposes, make the request at least ~500ms
      setTimeout(() => {
        dispatch(login(email, password));
      }, 500);
    })
    .catch(error => {
      // for UI purposes, make the request at least ~500ms
      setTimeout(() => {
        dispatch(registerError(error));
      }, 500);
    });
  };
}

export function getSession() {
  return dispatch => {
    dispatch(requestSession());

    const authKey = getAuthKey();

    return fetch(`${process.env.PRO_API}/user/session/`, {
      headers: {'accept': 'application/json', 'content-type': 'application/json', 'x-session-key': authKey},
      method: 'get'
    })
    // If the request itself failed (not just a non-200 response code), we didn't log in.
    .catch(() => dispatch(notLoggedIn()))
    .then(handleAPIResponse)
    .then(json => {
      dispatch(receiveSession(json));

      // HACK: temporarily makes watchlists work.
      userService.getWatchlists();
      userService.getAlerts();

      const user = json.User;
      const permissions = json.Permissions;

      bzTrack.identify(user.uid, {
        name: user.firstname + ' ' + user.lastname,
        email: user.email,
        phone: user.phone,
        username: user.username
      });

      // Olark
      olarkUpdateNickname(user.username);

      if (user.firstname === '' || user.lastname === '') {
        olarkUpdateFullName(user.username);
      } else {
        olarkUpdateFullName(user.firstname + ' ' + user.lastname);
      }

      olarkUpdateEmailAddress(user.email);
      olarkUpdatePhoneNumber(user.phone);

      if (permissions !== undefined) {
        // setup olark chat if they have permissions
        for (const permission of permissions) {
          if (permission === 'can_access_deskchat') {
            olarkShow();
            break;
          }
        }
      }

      // Sentry
      sentryUser(user.uid, user.email);
    })
    .catch(error => {
      switch (error.name) {
      case 'AuthError':
        dispatch(notLoggedIn());
        break;
      default:
        throw error;
      }
    });
  };
}

export function checkSession() {
  return dispatch => {
    const authKey = getAuthKey();

    if (!authKey) {
      dispatch(notLoggedIn());
      return;
    }

    dispatch(getSession());
  };
}

export function updateProfile(name, phone) {
  return dispatch => {
    dispatch(updateUser());

    const fullname = name.split(' ');
    const firstname = fullname.shift();
    const lastname = fullname.pop();
    const authKey = getAuthKey();

    return fetch(process.env.SERVICES_ROOT + '/services/user/profile', {
      headers: {'accept': 'application/json', 'content-type': 'application/json', 'x-device-key': authKey},
      body: JSON.stringify({firstname, lastname, phone}),
      method: 'put'
    })
    .then(handleAPIResponse)
    .then(json => dispatch(getSession()))
    .catch(error => {
      // for UI purposes, make the request at least ~500ms
      setTimeout(() => {
        dispatch(updateError(error));
      }, 500);
    });
  };
}
