import * as api from "./api";
import jwtDecode, { JwtPayload } from "jwt-decode";

const LOCAL_STORAGE_REFRESH_TOKEN = "refreshToken";

export function authenticate(login, password) {
  return (dispatch) => {
    return api
      .login(login, password)
      .then(({ accessToken, refreshToken, user }) => {
        dispatch({ type: "AUTHENTICATION_SUCCEEDED", accessToken, user });
        localStorage.setItem(LOCAL_STORAGE_REFRESH_TOKEN, refreshToken);
      });
  };
}

export function postAccount() {
  return async (dispatch) => {
    const refreshToken = localStorage.getItem(LOCAL_STORAGE_REFRESH_TOKEN);
    return api.postAccount(refreshToken).then((user) => {
      dispatch({ type: "ACCOUNT_SUCCEEDED", user });
    });
  };
}

export function postTracking(params) {
  return async (dispatch, getState) => {
    const accessToken = await checkToken(dispatch, getState);
    return api.postTracking(params, accessToken).then((res) => {
      return res;
    });
  };
}

export function deleteTracking(params) {
  return async (dispatch, getState) => {
    const accessToken = await checkToken(dispatch, getState);
    return api.deleteTracking(params, accessToken).then((res) => {
      return res;
    });
  };
}

export function getTrackingByDate(date) {
  return async (dispatch, getState) => {
    const accessToken = await checkToken(dispatch, getState);
    return api.getTracking(date, accessToken).then((res) => {
      return res;
    });
  };
}

export function getProductsByName(productName) {
  return async (dispatch, getState) => {
    const accessToken = await checkToken(dispatch, getState);
    return api.getProducts(productName, accessToken).then((res) => {
      return res;
    });
  };
}

export function signout(callback) {
  return (dispatch) => {
    dispatch({ type: "SIGNOUT" });
    localStorage.removeItem(LOCAL_STORAGE_REFRESH_TOKEN);
  };
}

export function signup(username: string, password: string) {
  return api.register(username, password);
}

function refreshToken(dispatch) {
  return new Promise((resolve, reject) => {
    const refreshToken = localStorage.getItem(LOCAL_STORAGE_REFRESH_TOKEN);
    return api
      .postToken(refreshToken)
      .then((res) => {
        dispatch({
          type: "TOKEN_REFRESH",
          accessToken: res.accessToken,
          username: res.username,
        });
        resolve(res.accessToken);
      })
      .catch((err) => {
        reject(err);
      });
  });
}

function isExpiredToken(token) {
  if (token) {
    const decodedToken = jwtDecode<JwtPayload>(token);

    if (decodedToken.exp) {
      if (Date.now() < decodedToken.exp * 1000) {
        return false;
      }
    }
  }

  return true;
}

async function checkToken(dispatch, getState) {
  let accessToken = getState().authentication.accessToken;

  if (isExpiredToken(accessToken)) {
    accessToken = await refreshToken(dispatch);
  }

  return accessToken;
}
