import dotProp from 'dot-prop-immutable';
import { get } from 'lodash';
import { fromJS } from 'immutable';
import {
  BEFORE_DISPATCH,
  DO_SUBMIT,
  HOC_CLEAR,
  REDUX_SET,
  REDUX_SET_FN,
  SUBMIT_ACKED,
  SUBMIT_FAILED,
  SUBMIT_SUCCEED,
  VARIABLES,
} from './internal/constants';
import helpers from './internal/helpers';

// The initial state of the App
const initialState = fromJS({});

const updateValue = (state, keyPath, value, isResagaStore) => {
  const [key, ...rest] = keyPath;
  const newValue = {};

  if (rest.length) {
    const values = state.get(key, {});
    newValue[key] = dotProp.set(values, rest, value);
  } else {
    newValue[key] = value;
  }

  if (isResagaStore) {
    return state.merge({
      [VARIABLES]: state.get(VARIABLES, fromJS({})).concat(newValue),
    });
  }

  return state.concat(newValue);
};

const getValue = (state, keyPath) => {
  const [name, key, ...rest] = keyPath;
  let currentValue;

  // immutable
  if (helpers.config.isResagaStore(name)) {
    currentValue = state.getIn([VARIABLES, key]);
  } else {
    currentValue = state.get(key);
  }

  // non-immutable
  if (rest.length && typeof currentValue === 'object') {
    currentValue = get(currentValue, rest);
  }

  return currentValue;
};

const getValues = (state, keyPath) => {
  const currentValue = getValue(state, keyPath);

  return [currentValue];
};

// const setValue = (state, { key, value, callback }) =>
//  state.mergeIn([VARIABLES, key], { value, callback });
const setValue = (state, { keyPath, value }) => {
  const [name, ...rest] = keyPath;

  let newValue;
  if (helpers.config.isResagaStore(name)) {
    newValue = updateValue(state.get(VARIABLES, initialState), rest, value, true);
  } else {
    newValue = updateValue(state, rest, value);
  }

  return state.merge(newValue);
};


const setValueWithFunction = (state, { keyPath, func }) => {
  const currentValues = getValues(state, keyPath);

  return setValue(state, { keyPath, value: func(...currentValues) });
};


/**
 * we store different forms in a page separately, distinguish by their `requestName`
 * and each form will have their own error and success status
 * @param state
 * @param action
 * @returns {any}
 */
export function reducers(state = initialState, action) {
  const trimmedType = helpers.reducer.trim(action.type);

  switch (trimmedType) {
    case BEFORE_DISPATCH:
      return state.set(action.requestName, {
        name: action.name,
        requestName: action.requestName,
        payload: action.payload,
        options: action.options,
        willLoad: true,
      });


    case DO_SUBMIT:
      return state.set(action.requestName, {
        isLoading: true,
      });


    case SUBMIT_FAILED:
      return state.set(action.requestName, {
        name: action.name,
        requestName: action.requestName,
        payload: action.payload,
        options: action.options,
        error: action.error,
      });


    case SUBMIT_SUCCEED:
      return state.set(action.requestName, {
        name: action.name,
        requestName: action.requestName,
        payload: action.payload,
        options: action.options,
        result: action.result,
        isSuccess: true,
      });


    case SUBMIT_ACKED:
      return state.delete(action.requestName);


    case HOC_CLEAR:
      return initialState;


    case REDUX_SET:
      return setValue(state, action);


    case REDUX_SET_FN:
      return setValueWithFunction(state, action);


    default:
      return state;
  }
}

const reducer = (name, customs) => helpers.reducer.wrapReducer(reducers, name, customs);

export default reducer;

@@ -434,23 +434,8 @@
 alue
-, isResagaStore
 ) =%3E
@@ -656,139 +656,8 @@
  %7D%0A%0A
-  if (isResagaStore) %7B%0A    return state.merge(%7B%0A      %5BVARIABLES%5D: state.get(VARIABLES, fromJS(%7B%7D)).concat(newValue),%0A    %7D);%0A  %7D%0A%0A
   re
@@ -1220,19 +1220,16 @@
 e%5D;%0A%7D;%0A%0A
-// 
 const se
@@ -1242,203 +1242,160 @@
  = (
-state, %7B key, value, callback %7D) =%3E%0A//  state.mergeIn(%5BVARIABLES, key%5D, %7B value, callback %7D);%0Aconst setValue = (state, %7B keyPath, value %7D) =%3E %7B%0A  const %5Bname, ...rest%5D = keyPath;%0A%0A  let newValue;
+pageStore, %7B keyPath, value %7D) =%3E %7B%0A  const %5Bname, ...rest%5D = keyPath;%0A%0A  // could be pageStore, could be under VARIABLES%0A  let valueStore = pageStore;%0A
 %0A  i
@@ -1443,35 +1443,29 @@
     
-newValue = updateValue(stat
+valueStore = pageStor
 e.ge
@@ -1494,44 +1494,55 @@
 ate)
-, rest, value, true);%0A  %7D else %7B%0A   
+;%0A  %7D%0A%0A  // upsert value from rest path%0A  const
  new
@@ -1561,20 +1561,25 @@
 teValue(
-stat
+valueStor
 e, rest,
@@ -1587,21 +1587,105 @@
 value);%0A
+%0A
   
-%7D%0A%0A
+// set updated value to store.VARIABLES%0A  if (helpers.config.isResagaStore(name)) %7B%0A  
   return
@@ -1685,20 +1685,134 @@
  return 
-stat
+pageStore.merge(%7B%0A      %5BVARIABLES%5D: newValue,%0A    %7D);%0A  %7D%0A%0A  // set updated value directly to store%0A  return pageStor
 e.merge(

Fix bug when setValue to resaga store (#286)