import { all, call, put, takeLatest } from '@redux-saga/core/effects';
import jwt from 'jsonwebtoken';
import history from '../utils/history';
import {
  AUTHENTICATE_USER,
  LOGIN_USER_FETCH,
  LOGOUT_USER,
  REFRESH_TOKEN,
  GENERATE_TOKEN,
} from '../actions/login/loginActionConstants';
import {
  attemptLogin,
  logoutUserRequest,
  refreshTokenRequest,
  generateTokenRequest,
} from '../../request/loginRequest';
import {
  fetchUserError,
  fetchUserSuccess,
  resetLoginState,
  updateUserToken,
} from '../actions/login/loginActions';
import { LOGIN_PAGE } from '../../constants/pages';
import { setUser } from '../actions/user/userActions';
import {
  addHeaderToken,
  removeHeaderToken,
} from '../../request';
import {
  IMPERSONATE_USER_UID,
  REGISTRATION_USER_UID,
} from '../../constants/sessionStorage';
import {
  JWT_REFRESH_TOKEN,
  JWT_TOKEN,
  REFRESH_TOKEN_CONST,
} from '../../constants/localStorage';
import {
  authScopeClearHelper,
  authScopeStringGetHelper,
  authScopeRemoveHelper,
  authScopeSetHelper,
} from '../../util/helpers/authScopeHelpers';
import { rejectErrorCodeHelper } from '../../util/helpers/rejectErrorCodeHelper';

function* fetchUser({ payload }) {
  try {
    const { data } = yield call(attemptLogin, payload);
    if (data.JwtToken) {
      const user = jwt.decode(data.JwtToken);
      yield call(authScopeSetHelper, JWT_TOKEN, data.JwtToken);
      yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken);
      yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.RefreshToken);
      yield call(addHeaderToken, data.JwtToken);
      yield put(setUser(user));
    }
    yield put(fetchUserSuccess(data));
    if (payload.handleApiResponseSuccess) {
      yield call(payload.handleApiResponseSuccess);
    }
  } catch (e) {
    if (e.response && e.response.data) {
      if (payload.handleApiResponseSuccess) {
        yield call(payload.handleApiResponseSuccess);
      }
      // const errorMessage = yield call(rejectErrorCodeHelper, e);
      // yield put(fetchUserError(errorMessage));
    }
  }
}
function* authenticateUser() {
  try {
    const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);

    if (!JwtToken) {
      yield call(history.push, LOGIN_PAGE);
    }

    return yield put(
      fetchUserSuccess({
        JwtToken,
      }),
    );
  } catch (error) {
    const errorMessage = yield call(rejectErrorCodeHelper, error);
    yield put(fetchUserError(errorMessage));
    yield call(authScopeRemoveHelper, JWT_TOKEN);
    yield call(authScopeRemoveHelper, JWT_REFRESH_TOKEN);
    yield call(authScopeRemoveHelper, REFRESH_TOKEN_CONST);
  }
}

function* logoutUser() {
  try {
    const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
    const user = jwt.decode(JwtToken);
    if (user) {
      yield call(logoutUserRequest, user.UserUid);
    }
  } catch (error) {
    console.log(error); // eslint-disable-line
  } finally {
    yield call(authScopeClearHelper);
    yield call(removeHeaderToken);
    yield put(resetLoginState());
    yield call(history.replace, LOGIN_PAGE);
  }
}

export function* refreshToken() {
  try {
    const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
    const JwtRefreshToken = yield call(
      authScopeStringGetHelper,
      JWT_REFRESH_TOKEN,
    );

    if (JwtToken && JwtRefreshToken) {
      const { data } = yield call(refreshTokenRequest, {
        JwtRefreshToken,
        JwtToken,
      });

      yield call(authScopeSetHelper, JWT_TOKEN, data.JwtToken);
      yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken);
      const user = jwt.decode(data.JwtToken);
      addHeaderToken(data.JwtToken);
      yield put(setUser(user));
      yield put(updateUserToken(data.JwtToken));
    }
  } catch (error) {
    yield call(logoutUser);
    console.log(error); // eslint-disable-line
  }
}

export function* generateToken({ payload }) {
  try {
    const { data } = yield call(generateTokenRequest, payload.data);
    const { JwtToken, JwtRefreshToken } = data;

    if (JwtToken && JwtRefreshToken) {
      yield call(authScopeSetHelper, JWT_TOKEN, data.JwtToken);
      yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken);

      if (payload.impersonate) {
        sessionStorage.setItem(IMPERSONATE_USER_UID, payload.accountUid);
      }

      if (payload.registration) {
        sessionStorage.setItem(REGISTRATION_USER_UID, payload.accountUid);
      }

      const user = jwt.decode(data.JwtToken);
      addHeaderToken(data.JwtToken);
      if (user) {
        yield put(setUser(user));
      }
      yield put(updateUserToken(data.JwtToken));

      if (payload.onSuccess) {
        yield call(payload.onSuccess);
      }
    }
  } catch (error) {
    yield call(logoutUser);
    console.log(error); // eslint-disable-line
  }
}

export default function* loginSaga() {
  yield all([
    takeLatest(LOGIN_USER_FETCH, fetchUser),
    takeLatest(AUTHENTICATE_USER, authenticateUser),
    takeLatest(LOGOUT_USER, logoutUser),
    takeLatest(REFRESH_TOKEN, refreshToken),
    takeLatest(GENERATE_TOKEN, generateToken),
  ]);
}
