import { createStore, compose, applyMiddleware } from 'redux';

import { composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from 'redux-saga';
import { routerMiddleware } from 'connected-react-router';

import { persistStore, getStoredState } from 'redux-persist';
import { CookieStorage, NodeCookiesWrapper } from 'redux-persist-cookie-storage';
import localeStorage from 'redux-persist/lib/storage'; // defaults to localStorage for web

import ServerCookies from 'cookies';

import { config } from 'config/general';
import rootSaga from 'store/rootSaga';
import { createUniversalHistory } from 'store/setup/history';
import createRootReducer from '../rootReducer';

interface StoreOption {
  initialState: object;
  middleware: object;
  req: object;
}

export const configNextStore = (initialState = {}) => {
  if (initialState._persist) delete initialState._persist;
  // Sagas
  const sagaMiddleware = createSagaMiddleware();

  const middleware = [];

  const history = createUniversalHistory();

  // Dev tools
  let composeEnhancers;

  if (config.locale) composeEnhancers = composeWithDevTools;
  else composeEnhancers = compose;

  // If needed
  const persistConfig = {
    key: config.storage.name,
    whitelist: config.storage.reducers,
    storage: localeStorage,
  };

  const rootReducer = createRootReducer(history, persistConfig);

  const preloadedState = initialState;

  const store = createStore(rootReducer, preloadedState, composeEnhancers(applyMiddleware(...[...middleware, sagaMiddleware])));

  // add persistor
  const persistor = persistStore(store);

  store._persistor = persistor;
  store._sagaRun = sagaMiddleware.run;

  // Launch main saga
  sagaMiddleware.run(rootSaga);

  return store;
};

export const configServerStore = async (options: StoreOption = {}) => {
  const { req, res, middleware } = options;

  // Sagas
  const sagaMiddleware = createSagaMiddleware();

  const history = createUniversalHistory(req);
  // Dev tools
  const composeEnhancers = compose;

  let preloadedState = {};
  let rootReducer;
  if (config.serverPersistStorage) {
    const cookieJar = new NodeCookiesWrapper(new ServerCookies(req, res));

    // If needed
    const persistConfig = {
      key: config.storage.name,
      whitelist: config.storage.reducers,
      storage: new CookieStorage(cookieJar /* , options */),
      // stateReconciler(inboundState, originalState) {
      //   // Ignore state from cookies, only use preloadedState from window object
      //   return originalState;
      // },
    };

    // Server only
    try {
      preloadedState = await getStoredState(persistConfig);
    } catch (e) {
      // getStoredState implementation fails when index storage item is not set.
      preloadedState = {};
    }

    rootReducer = createRootReducer(history, persistConfig);
  } else {
    rootReducer = createRootReducer(history);
  }

  const store = createStore(
    rootReducer,
    preloadedState,
    composeEnhancers(applyMiddleware(...[...(middleware || []), sagaMiddleware, routerMiddleware(history)])),
  );

  // run saga
  sagaMiddleware.run(rootSaga);

  const setup = {
    store,
    history,
    sagaRun: sagaMiddleware.run,
  };
  return setup;
};

export default configServerStore;
