import React from "react";
import PropTypes from "prop-types";
import { authenticate, invalidate, validateToken } from "../utils/identity";

var UserStateContext = React.createContext();
var UserDispatchContext = React.createContext();

function userReducer(state, action) {
  switch (action.type) {
    case "LOGIN_SUCCESS":
      return { ...state, ...action.payload, authenticated: true };
    case "SIGN_OUT_SUCCESS":
      return { ...state, authenticated: false };
    case "LOGIN_FAILURE":
      return {
        ...state,
        authenticated: false,
        messageCode: action.payload?.messageCode
      };
    default: {
      throw new Error(`Unhandled action type: ${action.type}`);
    }
  }
}

function UserProvider({ children }) {
  const { valid, token } = validateToken();
  var [state, dispatch] = React.useReducer(userReducer, {
    authenticated: valid === true,
    token
  });

  return (
    <UserStateContext.Provider value={state}>
      <UserDispatchContext.Provider value={dispatch}>
        {children}
      </UserDispatchContext.Provider>
    </UserStateContext.Provider>
  );
}

UserProvider.propTypes = {
  children: PropTypes.node
};

function useUserState() {
  var context = React.useContext(UserStateContext);
  if (context === undefined) {
    throw new Error("useUserState must be used within a UserProvider");
  }
  return context;
}

function useUserDispatch() {
  var context = React.useContext(UserDispatchContext);
  if (context === undefined) {
    throw new Error("useUserDispatch must be used within a UserProvider");
  }
  return context;
}

function setLoginFailed(dispatch, setError, setIsLoading, messageCode) {
  dispatch({ type: "LOGIN_FAILURE", payload: { messageCode } });
  setError(true);
  setIsLoading(false);
}

function loginUser(dispatch, login, password, history, setIsLoading, setError) {
  setError(false);
  setIsLoading(true);

  if (!!login && !!password) {
    authenticate(login, password).then((response) => {
      if (response.status === "SUCCESS") {
        setError(null);
        setIsLoading(false);
        dispatch({ type: "LOGIN_SUCCESS", payload: { token: response.token } });
      } else if (response.status === "BAD_CREDENTIALS") {
        setLoginFailed(
          dispatch,
          setError,
          setIsLoading,
          "Login.IncorrectCredentials"
        );
      }
    });

    history.push("/dashboard");
  } else {
    setLoginFailed(dispatch, setError, setIsLoading, "Login.EmptyCredentials");
  }
}

function signOut(dispatch, history) {
  invalidate();
  dispatch({ type: "SIGN_OUT_SUCCESS" });
  history.push("/login");
}

export { UserProvider, useUserState, useUserDispatch, loginUser, signOut };
