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_ADMIN,
  LOGOUT_USER,
  REFRESH_TOKEN,
} from "../actions/login/loginActionConstants";
import {
  attemptLogin,
  logoutAdminRequest,
  logoutUserRequest,
} from "../../request/loginRequest";
import {
  fetchUserError,
  fetchUserSuccess,
  resetLoginState,
  setUserJwtToken,
} from "../actions/login/loginActions";
import { ADMIN_LOGIN_PAGE, LOGIN_PAGE } from "../../constants/pages";
import { addHeaderToken, removeHeaderToken } from "../../request";
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";
import i18next from "i18next";
import { attemptFetchProfile } from "../../request/profileRequest";
import {
  clearProfile,
  setMineProfile,
} from "../actions/profile/profileActions";
import { clearOffers } from "../actions/offers/offersActions";
import { clearChat } from "../actions/chat/chatActions";

function* fetchLogin({ payload }) {
  try {
    const isAdmin = payload.isAdmin;
    // delete payload.isAdmin
    const dataFromBe = yield call(attemptLogin, payload);
    const data = dataFromBe?.data;
    if (data?.token) {
      const token = data.token;
      const refresh = data.refresh;
      const tokenDecoded = jwt.decode(token);
      const refreshDecoded = jwt.decode(refresh);
      if (isAdmin && !tokenDecoded.roles.includes("Admin")) {
        throw Error("Not an admin login on /login");
      }
      const accessToken = {
        token: token,
        exp: tokenDecoded.exp,
        roles: tokenDecoded.roles,
      };
      const refreshToken = {
        token: refresh,
        exp: refreshDecoded.exp,
      };
      const userId = tokenDecoded._id;
      yield call(authScopeSetHelper, JWT_TOKEN, token);
      yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, refresh);
      yield call(addHeaderToken, token);
      const profileData = yield call(attemptFetchProfile, userId);
      if (profileData) yield put(setMineProfile(profileData.data));
      yield put(
        fetchUserSuccess({
          jwtToken: accessToken,
          refreshToken: refreshToken,
          userId,
        })
      );
      if (payload.handleApiResponseSuccess) {
        yield call(payload.handleApiResponseSuccess);
      }
    }
  } catch (e) {
    console.dir(e);
    if (e.message) {
      yield put(fetchUserError(e.message));
    }
    if (e.response && e.response.data) {
      if (payload.handleApiResponseError) {
        yield call(payload.handleApiResponseError, e.response.status);
      }
      console.log(e.response.status);
      let errorMessage = yield call(rejectErrorCodeHelper, e.response.status);
      if (e.response.status === 401 || e.response.status === 404) {
        errorMessage = i18next.t("login.wrongCredentials", {
          lng: "rs",
        });
      }
      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);
  }
}

function* logout(payload) {
  try {
    const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
    const user = yield call(jwt.decode, JwtToken);
    if (user) {
      const requestBody = { token: JwtToken };
      yield call(logoutUserRequest, requestBody);
      yield call(payload.payload);
    }
  } catch (error) {
    console.dir(error); // eslint-disable-line
  } finally {
    yield call(authScopeClearHelper);
    yield call(removeHeaderToken);
    yield put(resetLoginState());
    yield call(history.replace, LOGIN_PAGE);
    yield put(clearProfile());
    yield put(clearOffers());
    yield put(clearChat());
  }
}
function* logoutAdmin(payload) {
  try {
    const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
    const user = yield call(jwt.decode, JwtToken);
    if (user) {
      const requestBody = { token: JwtToken };
      yield call(logoutAdminRequest, requestBody);
      yield call(payload.payload);
    }
  } catch (error) {
    console.dir(error); // eslint-disable-line
  } finally {
    yield call(authScopeClearHelper);
    yield call(removeHeaderToken);
    yield put(resetLoginState());
    yield call(history.replace, ADMIN_LOGIN_PAGE);
    yield put(clearProfile());
    yield put(clearOffers());
    yield put(clearChat());
  }
}
function* refreshUserToken({ payload }) {
  try {
    const newTokenDecoded = jwt.decode(payload);

    yield put(
      setUserJwtToken({
        token: payload,
        exp: newTokenDecoded.exp,
        roles: newTokenDecoded.roles,
      })
    );
    yield call(addHeaderToken, payload);
    yield call(authScopeSetHelper, JWT_TOKEN, payload);
    return true;
  } catch (e) {
    console.dir(e);
    return false;
  }
}

export default function* loginSaga() {
  yield all([
    takeLatest(LOGIN_USER_FETCH, fetchLogin),
    takeLatest(AUTHENTICATE_USER, authenticateUser),
    takeLatest(LOGOUT_USER, logout),
    takeLatest(REFRESH_TOKEN, refreshUserToken),
    takeLatest(LOGOUT_ADMIN, logoutAdmin),
  ]);
}
