/**
 * Optimistically merges new state with existing state while
 * allowing for rollbacks and commits
 *
 * @param {Object} state The current state of the store
 * @param {Object} action The action that was triggered
 * @param {Object} options The action lifecycle mutation functions
 * @param {Function} options.forward Function which returns state
 * object to be merged with current state immediately after
 * action is triggered
 * @param {Function} options.back Function which returns state
 * object to be merged with current state in the case of an error
 * from server
 * @param {Function} [options.commit] Function which returns state
 * object to be merged with current state upon success response
 * from server
 *
 * @returns {Object} New state object
 */
export default function mergeStateWithRollback(state, action, { forward, back, commit }) {
    if (!action.hasOwnProperty('meta')) {
        return state;
    } else if (!action.meta.isPending && action.payload && action.payload.error) {
        return {
            ...state,
            ...back(),
        };
    } else if (action.meta.isPending) {
        return {
            ...state,
            ...forward(),
        };
    }

    if (commit) {
        return {
            ...state,
            ...commit(),
        };
    }

    return state;
}
