import { routerRedux } from 'dva/router';
import { parse } from 'qs';
import { ReduxAction, ReduxSagaEffects } from '@interfaces';
import { config, networkUtils } from '../utils';
import { getMenu, getPrincipal, getTodoCnt, logout } from '@services/app';
import * as socketService from '@services/common/socket';

import Raven from 'raven-js';

const { prefix } = config;

let socketInstance = null;

export default {
  namespace: 'app',
  state: {
    user: null,
    menu: null,
    perms: null,
    msgCnt: { warn: 0, info: 0, todo: 0 },
    menuPopoverVisible: false,
    siderFold: localStorage.getItem(`${prefix}_siderFold`) === 'true',
    darkTheme: true,
    isNavbar: document.body.clientWidth < 769,
    navOpenKeys: JSON.parse(sessionStorage.getItem(`${prefix}_navOpenKeys`)) || [],
    // navOpenKeys: ['home'],
  },
  subscriptions: {
    setup({ dispatch, history }) {
      networkUtils.csrf().then(() => {
        if (config.openPages && config.openPages.indexOf(location.pathname) !== -1) {
          // console.log('不直接进入app');
          // console.dir("app",location);
        } else {
          dispatch({ type: 'query' });
        }
      }).catch((error) => {
        dispatch(routerRedux.push('/600'));
      });

      let tid;
      window.onresize = () => {
        clearTimeout(tid);
        tid = setTimeout(
          () => {
            dispatch({ type: 'changeNavbar' });
          },
          300);
      };
    },

    socket({ dispatch }: object) {   // socket相关
      if (config.openPages && config.openPages.indexOf(location.pathname) === -1) {

        socketInstance = socketService.listen((data) => {
          switch (data.type) {
            case 'connect':
              if (data.state === 'success') {
                dispatch({
                  type: 'connectSuccess',
                });
              } else {
                dispatch({
                  type: 'connectFail',
                });
              }
              break;
            case 'msgCnt':
              dispatch({
                type: 'updateState',
                payload: { msgCnt: data.payload },
              });
              break;
            case 'updateMsgCnt':
              dispatch({
                type: 'updateMsgCnt',
                payload: data.payload,
              });
              break;
          }
        });


      }
    },
  },

  effects: {
    * query({ payload }: ReduxAction, { call, put }: ReduxSagaEffects) {
      const data = yield call(getPrincipal, parse(payload));
      // console.dir(data);

      if (data.success && data.data) {
        Raven.setUserContext({
          username: data.data.userName,
          id: data.data.id,
        });

        const menu = yield call(getMenu, parse(payload));
        if (menu.success) {
          yield put({
            type: 'updateState',
            payload: {
              user: data.data,
              menu: menu.data.filter((m) => m.menuType === 'M' || m.menuType === 'B'),
              perms: menu.data.filter((m) => (m.menuType === 'F' || m.menuType === 'L')),
            },
          });
        }

        if (location.pathname === '/login' || location.pathname === '/validate') {
          yield put(routerRedux.push('/dashboard'));
        }
      } else if (config.openPages && config.openPages.indexOf(location.pathname) < 0) {
        // let from = location.pathname
        // window.location = `${location.origin}/login?from=${from}`
        window.location = `${location.origin}/login`;
      }
    },

    * getPrincipal({ payload }: ReduxAction, { call, put }: ReduxSagaEffects) {
      const data = yield call(getPrincipal, parse(payload));
      if (data.success && data.data) {
        yield put({
          type: 'updateState',
          payload: { user: data.data },
        });
      }
    },

    * getCnt({ payload }: ReduxAction, { call, put }: ReduxSagaEffects) {
      const data = yield call(getTodoCnt, parse(payload));
      if (data.success && data.data) {
        yield put({
          type: 'updateState',
          payload: { user: data.data },
        });
      }
    },

    * logout({ payload }: ReduxAction, { call, put }: ReduxSagaEffects) {
      const data = yield call(logout, parse(payload));
      if (data.success) {
        socketService.close(socketInstance);
        sessionStorage.setItem(`${prefix}_navOpenKeys`, JSON.stringify(['home']));
        yield put(routerRedux.push('/login'));
      } else {
        throw (data);
      }
    },

    * changeNavbar({ payload }: ReduxAction, { call, put, select }: ReduxSagaEffects) {
      const { app } = yield (select(_ => _));
      const isNavbar = document.body.clientWidth < 769;
      if (isNavbar !== app.isNavbar) {
        yield put({ type: 'handleNavbar', payload: isNavbar });
      }
    },
  },
  reducers: {
    updateState(state: object, action: ReduxAction) {
      // console.dir(state);
      // console.dir(action);
      return {
        ...state,
        ...action.payload,
      };
    },

    updateInfo(state: object, action: ReduxAction) {
      return {
        ...state,
        ...action.payload,
      };
    },

    switchSider(state: object) {
      localStorage.setItem(`${prefix}_siderFold`, !state.siderFold);
      return {
        ...state,
        siderFold: !state.siderFold,
      };
    },

    switchTheme(state: object) {
      localStorage.setItem(`${prefix}_darkTheme`, !state.darkTheme);
      return {
        ...state,
        darkTheme: !state.darkTheme,
      };
    },

    switchMenuPopver(state: object) {
      return {
        ...state,
        menuPopoverVisible: !state.menuPopoverVisible,
      };
    },

    handleNavbar(state: object, { payload }: ReduxAction) {
      return {
        ...state,
        isNavbar: payload,
      };
    },

    handleNavOpenKeys(state: object, { payload: navOpenKeys }: ReduxAction) {
      return {
        ...state,
        ...navOpenKeys,
      };
    },

    updateMsgCnt(state: object, { payload }: ReduxAction) {
      const { type, mode } = payload;
      const newMsgCng = Object.assign({}, state.msgCnt);
      if (mode === 'add') {
        newMsgCng[type] = newMsgCng[type] + 1;
        if (type === 'todo') {
          newMsgCng['info'] = newMsgCng['info'] + 1;
        }
      } else if (mode === 'minus') {
        newMsgCng[type] = newMsgCng[type] > 0 ? newMsgCng[type] - 1 : 0;
      }
      return {
        ...state,
        msgCnt: newMsgCng,
      };
    },
  },
};
