import { all, call, put, takeLatest } from "@redux-saga/core/effects";
import jwt from "jsonwebtoken";
import history from "../utils/history";
import {
  AUTHENTICATE_USER,
  LOGIN_GOOGLE_USER_FETCH,
  LOGIN_USER_FETCH,
  LOGOUT_USER,
  REFRESH_TOKEN,
  GENERATE_TOKEN,
  FORGOT_PASSWORD,
  RESET_PASSWORD,
} from "../actions/login/loginActionConstants";
import {
  attemptGoogleLogin,
  attemptLogin,
  logoutUserRequest,
  refreshTokenRequest,
  generateTokenRequest,
  forgetPasswordEmailSend,
  sendResetPassword,
} from "../../request/loginRequest";
import {
  fetchGoogleUserSuccess,
  fetchUserError,
  fetchUserSuccess,
  forgetPasswordSuccess,
  resetLoginState,
  updateUserToken,
} from "../actions/login/loginActions";
import { BASE_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) {
      yield call(authScopeSetHelper, JWT_TOKEN, data.token);
      yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.refreshToken);
      yield call(addHeaderToken, data.token);
      yield put(setUser(data));
    }
    yield put(fetchUserSuccess(data));
    if (payload.handleApiResponseSuccess) {
      yield call(payload.handleApiResponseSuccess);
    }
  } catch (e) {
    if (e.response && e.response.data) {
      if (payload.handleApiResponseFailed) {
        yield call(payload.handleApiResponseFailed);
      }
      const errorMessage = yield call(rejectErrorCodeHelper, e);
      yield put(fetchUserError(errorMessage));
    }
  }
}

function* forgetPassword({ payload }) {
  try {
    const { data } = yield call(forgetPasswordEmailSend, payload);
    yield put(forgetPasswordSuccess(data));
    if (payload.handleApiResponseSuccess) {
      yield call(payload.handleApiResponseSuccess);
    }
  } catch (e) {
    if (e.response && e.response.data) {
      if (payload.handleApiResponseFailed) {
        yield call(payload.handleApiResponseFailed);
      }
      const errorMessage = yield call(rejectErrorCodeHelper, e);
      yield put(fetchUserError(errorMessage));
    }
  } finally {
    // console.log('Done')
  }
}

function* resetPassword({ payload }) {
  try {
    const { data } = yield call(sendResetPassword, payload);
    yield put(forgetPasswordSuccess(data));
    if (payload.handleApiResponseSuccess) {
      yield call(payload.handleApiResponseSuccess);
    }
  } catch (e) {
    if (e.response && e.response.data) {
      if (payload.handleApiResponseFailed) {
        yield call(payload.handleApiResponseFailed);
      }
      const errorMessage = yield call(rejectErrorCodeHelper, e);
      yield put(fetchUserError(errorMessage));
    }
  }
}

function* fetchGoogleUser({ payload }) {
  try {
    const { data } = yield call(attemptGoogleLogin, payload);
    if (data.token) {
      // const user = jwt.decode(data.token);
      yield call(authScopeSetHelper, JWT_TOKEN, data.token);
      yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.refreshToken);
      yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.refreshToken);

      yield call(addHeaderToken, data.token);
      yield put(setUser(data));
    }
    yield put(fetchGoogleUserSuccess(data));
    if (payload.handleApiResponseSuccess) {
      yield call(payload.handleApiResponseSuccess);
    }
  } catch (e) {
    if (e.response && e.response.data) {
      if (payload.handleApiResponseFailed) {
        yield call(payload.handleApiResponseFailed);
      }
      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, BASE_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.id);
    }
  } catch (error) {
    console.log(error); // eslint-disable-line
  } finally {
    yield call(authScopeClearHelper);
    yield call(removeHeaderToken);
    yield put(resetLoginState());
    yield call(history.replace, BASE_PAGE);
  }
}

export function* refreshToken() {
  try {
    const token = yield call(authScopeStringGetHelper, JWT_TOKEN);
    const refreshToken = yield call(
      authScopeStringGetHelper,
      REFRESH_TOKEN_CONST
    );

    if (token && refreshToken) {
      const { data } = yield call(refreshTokenRequest, {
        refreshToken,
        token,
      });

      yield call(authScopeSetHelper, JWT_TOKEN, data.data.token);
      addHeaderToken(data.data.token);
      yield put(setUser(data.data));
    }
  } catch (error) {
    localStorage.removeItem(JWT_TOKEN);
    localStorage.removeItem(REFRESH_TOKEN_CONST);
    yield call(history.replace, BASE_PAGE);
  }
}

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(FORGOT_PASSWORD, forgetPassword),
    takeLatest(RESET_PASSWORD, resetPassword),
    takeLatest(LOGIN_GOOGLE_USER_FETCH, fetchGoogleUser),
    takeLatest(AUTHENTICATE_USER, authenticateUser),
    takeLatest(LOGOUT_USER, logoutUser),
    takeLatest(REFRESH_TOKEN, refreshToken),
    takeLatest(GENERATE_TOKEN, generateToken),
  ]);
}
