import { createAction, createReducer } from '@reduxjs/toolkit';
import * as apiActions from './apiActions';

// Will allow us to have consistent key if we decide to save JWT to
// local storage instead of cookie
const tokenKey = 'token';

// Keep whatever user specific session data we want to use on the front end
const initialState = {
  isLoading: false, // Can trigger loading indicator based on flag
  lastFetch: null, // We can timestamp here to run comparisons for caching
  username: '',
  email: '',
  password: '',
  isLoggedIn: false,
  wantToSignUp: true,
  user: {
    username: '',
    email: '',
    password: '',
    joinedon: '',
  },
};

/*
Action Types here are unnecessary as everything's in the same file, but
it's my preference to ensure consistency. Easily Changed if needed.
*/

// Action Types
const USERS_REQUEST = 'usersRequest';
const USERS_REQUEST_FAILED = 'usersRequestFailed';
const RECEIVED_USER = 'receivedUser';
const SET_IS_LOGGED_IN = 'setIsLoggedIn';
const SET_USERNAME = 'setUsername';
const SET_EMAIL = 'setEmail';
const SET_PASSWORD = 'setPassword';
const UPDATE_USER = 'updateUser';

/*
Create action is part of Reduxjs toolkit and will automatically create
a function that returns an object with a type property set to the argument
passed to createAction, and a payload property consistent with whatever
argument is passed to the created function. 
ie: usersRequest = createAction('usersRequestX') === 

function usersRequest(actionPayload) {
  return {
    type: 'usersRequestX',
    payload: actionPayload
  }
}
*/

// Action Creators
export const usersRequest = createAction(USERS_REQUEST); // no payload needed
export const usersRequestFailed = createAction(USERS_REQUEST_FAILED); // no payload needed
export const receivedUser = createAction(USERS_REQUEST_FAILED); // needs userObj as payload
export const setIsLoggedIn = createAction(SET_IS_LOGGED_IN);
export const setUsername = createAction(SET_USERNAME);
export const setEmail = createAction(SET_EMAIL);
export const setPassword = createAction(SET_PASSWORD);
export const updateUser = createAction(UPDATE_USER);
/*
Create reducer is a redux toolkit function that maps function definitions
to action types and returns a single reducer for export.
Under the hood it uses a library called IMMER that will
allow us to right simpler code without having to worry about mutating state.
I believe it will also return state by default if no action types match.
*/

// Reducers
const usersReducer = createReducer(initialState, {
  [USERS_REQUEST]: usersRequestCase,
  [USERS_REQUEST_FAILED]: usersRequestFailedCase,
  [RECEIVED_USER]: receivedUserCase,
  [SET_IS_LOGGED_IN]: setIsLoggedInCase,
  [SET_USERNAME]: setUsernameCase,
  [SET_EMAIL]: setEmailCase,
  [SET_PASSWORD]: setPasswordCase,
  [UPDATE_USER]: updateUserCase,
});

// Reducer Cases
function usersRequestCase(state, action) {
  console.log('in reducer - type', action.type);
  console.log('in reducer - payload', action.payload);

  state.isLoading = true;
}

function usersRequestFailedCase(state, action) {
  state.isLoading = false;
}

function receivedUserCase(state, action) {
  const { data: userInfo } = action.payload;
  state.user = userInfo;
  state.isLoading = false;
}

function setIsLoggedInCase(state, action) {
  state.isLoggedIn = action.payload;
}

function setUsernameCase(state, action) {
  state.username = action.payload;
}

function setEmailCase(state, action) {
  state.email = action.payload;
}

function setPasswordCase(state, action) {
  state.password = action.payload;
}

function updateUserCase(state, action) {
  const resetUser = {
    username: '',
    email: '',
    password: '',
    joinedon: '',
  };
  state.user = { ...resetUser, ...action.payload };
}

export default usersReducer;

/*
Most of the time we user action creators to return objects. We dispatch the
objects returned by action creators to our reducers to update state. Sometimes 
we want to execute logic though and we can't do that with simple action creators and
the objects they return. 
Redux Toolkit comes with a built in middleware called THUNK. THUNK allows us to 
pass functions as actions. Thunk will check the type of an action, if it is a function, 
thunk will CALL THAT FUNCTION. Below are action generators (I made up that term, it's not
real). These, when called will return functions that, when called, return a specific action
object. These action generators essentially return action creators, but allow us to pass
parameters to those action creators as payload. In this case, we can create one action
for an API call but customize the data and type based on what we give the action generator.
Confusing, but solid practice and implacations extend beyond fetch requests. 
*/

// Action Generators -- Functions for API calls

const { apiCallRequested } = apiActions;
const usersUrl = '/whateverTheBackendNeeds';
const loginUrl = '/whateverTheBackendNeeds';

// Returns function that, when called creates an API action object with the following payload
export const login = loginObj =>
  apiCallRequested({
    url: loginUrl,
    method: 'post',
    data: loginObj, // Likely needs userName and password
    onStart: USERS_REQUEST, // These three props are actions to be dispatched by our API middleware
    onSuccess: RECEIVED_USER,
    onError: USERS_REQUEST_FAILED,
  });