import http from 'utils/fetch';
import message from 'components/message';
import { api } from 'constants/config';
import { actionTypes } from 'constants/action-types';
import { getScreen, updateLayersKey } from 'models/screen';
import { hybridUpdate } from 'models/component';
import { deepUpdate, updateByKey } from 'utils/data-helper';
import { isInSelected, isContainSelected, range, toObject } from 'utils/layer';
import { getTopScreenId } from 'utils/screen';
import { componentOperator } from 'utils/component';
import { getId } from 'utils/interaction';
import { isAppPage } from 'utils/utils';
import { CreateAppReducerTpe } from './create-app.types';

export function getScreenData(id, signal) {
  return async (dispatch) => {
    dispatch({
      type: actionTypes.SCREEN_EDIT_GET_START
    });

    const result = await dispatch(getScreen(id, signal));

    if (result) {
      dispatch({
        type: actionTypes.SCREEN_EDIT_GET_SUCCESS
      });
    } else {
      dispatch({
        type: actionTypes.SCREEN_EDIT_GET_FAILURE
      });
    }

    return result;
  };
}

export function selectLayers(selected) {
  return (dispatch) => {
    selected = Array.isArray(selected) ? selected : [selected];
    dispatch({
      type: actionTypes.LAYER_SELECT,
      payload: {
        selected
      }
    });
  };
}

export function selectLayersWithCtrl(layerId) {
  return (dispatch, getState) => {
    const { createApp, screensById } = getState();
    const { id, layersSelected } = createApp;
    const screen = screensById[id];
    if (screen) {
      const { layers } = screen;
      if (layersSelected.indexOf(layerId) > -1) {
        const newSelected = layersSelected.filter((d) => d !== layerId);
        dispatch({
          type: actionTypes.LAYER_SELECT,
          payload: {
            selected: newSelected
          }
        });
      } else {
        if (
          !isInSelected({ layers, selected: layersSelected, id: layerId }) &&
          !isContainSelected({ layers, selected: layersSelected, id: layerId })
        ) {
          dispatch({
            type: actionTypes.LAYER_SELECT,
            payload: {
              selected: layersSelected.concat(layerId)
            }
          });
        }
      }
    }
  };
}

export function selectLayersWithShift(layerId) {
  return (dispatch, getState) => {
    const { createApp, screensById } = getState();
    const { id, layersSelected } = createApp;
    const screen = screensById[id];

    if (screen) {
      const { layers } = screen;
      if (layersSelected.length) {
        const lastSelectedId = layersSelected[layersSelected.length - 1];
        if (layerId === lastSelectedId) {
          return;
        }
        const layersById: any = toObject(layers);
        const rangeIds = range({ layers, startId: lastSelectedId, endId: layerId });
        // 过滤掉重复选中的
        const all: any = Array.from(new Set(layersSelected.concat(rangeIds)));
        const allWithoutInGroup = all.filter((d) => !layersById[d].groupPath.some((v) => all.indexOf(v) > -1));

        dispatch({
          type: actionTypes.LAYER_SELECT,
          payload: {
            selected: allWithoutInGroup
          }
        });
      } else {
        const all = layers.map((d) => d.id);
        dispatch({
          type: actionTypes.LAYER_SELECT,
          payload: {
            selected: all
          }
        });
      }
    }
  };
}

export function selectLayerWithScrollIntoView(layerId) {
  return (dispatch, getState) => {
    layerId = isNaN(+layerId) ? layerId : +layerId;
    const { createApp, screensById } = getState();
    const { id, layersSelected } = createApp;
    if (layersSelected.length === 1 && layersSelected[0] === layerId) {
      return;
    }

    const screen = screensById[id];
    const { layers } = screen;
    const layersById = toObject(layers);
    const layer = layersById[layerId];

    if (layer) {
      const groupPath = layer.groupPath;
      const updates: any = [];
      groupPath.forEach((d) => {
        if (layersById[d].collapsed) {
          updates.push({ id: d, key: 'collapsed', value: false });
        }
      });

      if (updates.length) {
        dispatch(updateLayersKey({ values: updates }));
      }

      dispatch({
        type: actionTypes.LAYER_SELECT,
        payload: {
          selected: [layerId]
        }
      });

      const selectDom = document.getElementById(`layer_${layerId}`);
      if (selectDom) {
        selectDom.scrollIntoView({
          behavior: 'auto',
          block: 'center'
        });
      }
    }
  };
}

export function selectChild(id) {
  return {
    type: actionTypes.CHILD_SELECT,
    payload: {
      id
    }
  };
}

export function getFilterScreenId(pathname = window.location.pathname) {
  const pathnameArr = pathname.split('/');
  if (/\/app\/edit\/[0-9]+\/[0-9]+/.test(pathname)) {
    const i = pathnameArr.findIndex((d) => d === 'edit');
    return +pathnameArr[i + 1];
  } else {
    return +pathnameArr[pathnameArr.length - 1];
  }
}

// 消息通知入口/过滤器使用的组件/搜索的组件 快速选择组件并展开折叠的组以及滚动到当前视图
export function selectComponentWithId(id, history) {
  return async (dispatch, getState) => {
    const { componentsById, createApp, screensById } = getState();
    const { id: currentScreenId } = createApp;
    const { parent, screenId } = componentsById[id];
    const { panelId, mobileId } = screensById[screenId];
    const _isAppPage = isAppPage();

    if (screenId != currentScreenId) {
      if (panelId) {
        const topScreenId = getTopScreenId();
        if (_isAppPage) {
          const mobileId = getFilterScreenId();
          history.push(`/app/edit/${mobileId}/${topScreenId}/panel_${panelId}/${screenId}`);
        } else {
          history.push(`/create/${topScreenId}/panel_${panelId}/${screenId}`);
        }
      } else if (mobileId) {
        history.push(`/app/edit/${mobileId}/${screenId}`);
      } else {
        history.push(`/create/${screenId}`);
      }
    }

    if (parent) {
      await dispatch(selectLayerWithScrollIntoView(parent));
      dispatch(selectChild(id));
    } else {
      dispatch(selectLayerWithScrollIntoView(id));
    }
  };
}

export function resetSelect() {
  return (dispatch, getState) => {
    const { createApp } = getState();
    const { layersSelected } = createApp;
    if (layersSelected.length) {
      dispatch({
        type: actionTypes.SELECT_RESET
      });
    }
  };
}

export function resetChildSelect() {
  return {
    type: actionTypes.CHILD_SELECT_RESET
  };
}

export function changeScale(scale) {
  return (dispatch, getState) => {
    const { createApp } = getState();
    if (scale !== createApp.scale) {
      dispatch({
        type: actionTypes.SCREEN_SCALE_CHANGE,
        payload: {
          scale
        }
      });
    }
  };
}

export function changeNodeScale(scale) {
  return (dispatch, getState) => {
    const { createApp } = getState();
    if (scale !== createApp.nodeScale) {
      dispatch({
        type: actionTypes.SCREEN_NODE_SCALE_CHANGE,
        payload: {
          nodeScale: scale
        }
      });
    }
  };
}

// 修改组配置信息
export function updateGroupConfig(changes) {
  return (dispatch, getState) => {
    const { createApp } = getState();
    const { id: screenId } = createApp;

    return http
      .post(api.screenLayersChange, {
        id: screenId,
        configs: changes
      })
      .then((result) => {
        if (!result) {
          message.error('更新失败');
          return;
        }
        dispatch({
          type: actionTypes.LAYER_UPDATE,
          payload: {
            id: screenId,
            layers: result
          }
        });
      });
  };
}

// 左侧面板开关
export function toggleLeftCollapsed() {
  return {
    type: actionTypes.SCREEN_LEFT_COLLAPSED
  };
}

// 右侧面板开关
export function toggleRightCollapsed() {
  return {
    type: actionTypes.SCREEN_RIGHT_COLLAPSED
  };
}

// 撤销配置修改
export function undoConfigChange() {
  return (dispatch, getState) => {
    const { createApp } = getState(),
      { undoReducers } = createApp;
    if (undoReducers.length > 0) {
      const undoRecord = undoReducers.shift();
      if (undoRecord) {
        const panels: any = [];
        const comps: any = [];
        undoRecord.forEach((item) => {
          if (componentOperator.isComponent(item.id)) {
            comps.push({ componentId: item.id, updateData: item });
          } else {
            panels.push({ id: getId(item.id), updateData: { ...item, id: getId(item.id) } });
          }
        });
        dispatch(hybridUpdate({ component: comps, panel: panels }));
        dispatch(removeUndoConfig());
      }
    }
  };
}

// 添加撤销步骤
export function addUndoConfig({ list }) {
  return {
    type: actionTypes.ADD_UNDO_CONFIG,
    payload: { list }
  };
}

// 撤销操作
export function removeUndoConfig() {
  return {
    type: actionTypes.REMOVE_UNDO_CONFIG
  };
}

// 清空
export function clearScreen() {
  return {
    type: actionTypes.CLEAR
  };
}

export function redirectScreen(id) {
  return async (dispatch, getState) => {
    const { screensById } = getState();
    const screen = screensById[id];

    if (!screen) {
      await dispatch(getScreen(id));
    }

    dispatch({
      type: actionTypes.SCREEN_REDIRECT,
      payload: {
        id: +id
      }
    });
  };
}

export function changeComponentConfigActiveKey(key) {
  return {
    type: actionTypes.COMPONENT_CONFIG_ACTIVE_KEY_CHANGE,
    payload: {
      componentConfigActiveKey: key
    }
  };
}

export function showComponentEditModal(componentId) {
  return {
    type: actionTypes.COMPONENT_EDIT_MODAL_SHOW,
    payload: {
      componentId
    }
  };
}

export function hideComponentEditModal() {
  return {
    type: actionTypes.COMPONENT_EDIT_MODAL_HIDE
  };
}

export function updateFocusMode({ focusMode }) {
  return (dispatch) => {
    dispatch({
      type: actionTypes.COMPONENT_EDIT_MODAL_FOCUS,
      payload: {
        focusMode
      }
    });
  };
}

export function openEdit(id) {
  return (dispatch, getState) => {
    const editId = id;

    dispatch({
      type: actionTypes.OPEN_EDIT,
      payload: {
        editId
      }
    });
  };
}

export function closeEdit() {
  return {
    type: actionTypes.CLOSE_EDIT
  };
}

const initialState: CreateAppReducerTpe = {
  id: null, // screenId
  loading: true,
  leftCollapsed: false,
  rightCollapsed: false,
  scale: 1,
  nodeScale: 1,
  layersSelected: [],
  componentsChildSelected: null,
  contextMenu: {
    visible: false,
    copyVisible: false,
    copyLoading: false,
    type: 'layer',
    top: 0,
    left: 0,
    layerOptions: []
  },
  undoReducers: [],
  // 单独显示图层id
  focusLayers: [],
  componentConfigActiveKey: '1',
  modalEdit: null,
  focusMode: false, //专注模式
  editId: null // 文本编辑标识
};

export default function reducer(state = initialState, { type, payload }): CreateAppReducerTpe {
  switch (type) {
    case actionTypes.SCREEN_EDIT_GET_START: {
      return { ...state, loading: true };
    }
    case actionTypes.SCREEN_EDIT_GET_SUCCESS: {
      return { ...state, loading: false };
    }
    case actionTypes.SCREEN_EDIT_GET_FAILURE: {
      return { ...state, loading: false };
    }
    case actionTypes.COMPONENT_EDIT_MODAL_FOCUS: {
      return {
        ...state,
        focusMode: payload.focusMode
      };
    }
    case actionTypes.SCREEN_REDIRECT: {
      return { ...state, id: payload.id };
    }
    case actionTypes.LAYER_SELECT: {
      return { ...state, layersSelected: payload.selected, componentsChildSelected: null };
    }
    case actionTypes.CHILD_SELECT: {
      return { ...state, componentsChildSelected: payload.id };
    }
    case actionTypes.SELECT_RESET: {
      return { ...state, componentsChildSelected: null, layersSelected: [] };
    }
    case actionTypes.CHILD_SELECT_RESET: {
      return { ...state, componentsChildSelected: null };
    }
    case actionTypes.SCREEN_SCALE_CHANGE: {
      return { ...state, scale: payload.scale };
    }
    case actionTypes.SCREEN_NODE_SCALE_CHANGE: {
      return {
        ...state,
        nodeScale: payload.nodeScale
      };
    }
    case actionTypes.SCREEN_LEFT_COLLAPSED: {
      return { ...state, leftCollapsed: !state.leftCollapsed };
    }
    case actionTypes.SCREEN_RIGHT_COLLAPSED: {
      return { ...state, rightCollapsed: !state.rightCollapsed };
    }
    case actionTypes.CLEAR: {
      return { ...state, layersSelected: [], id: null, componentsChildSelected: null, focusLayers: [] };
    }
    case actionTypes.CONTEXT_MENU_SHOW: {
      return updateByKey('contextMenu', deepUpdate({ ...payload, visible: true }, state.contextMenu), state);
    }

    case actionTypes.CONTEXT_MENU_HIDE: {
      return updateByKey('contextMenu', deepUpdate({ visible: false }, state.contextMenu), state);
    }

    case actionTypes.COPY_MODAL_SHOW: {
      return updateByKey('contextMenu', deepUpdate({ copyVisible: true, visible: false }, state.contextMenu), state);
    }

    case actionTypes.COPY_MODAL_HIDE: {
      return updateByKey('contextMenu', deepUpdate({ copyVisible: false }, state.contextMenu), state);
    }

    case actionTypes.CROSS_COPY_STATR: {
      return updateByKey('contextMenu', deepUpdate({ copyLoading: true }, state.contextMenu), state);
    }

    case actionTypes.CROSS_COPY_SUCCESS: {
      return updateByKey('contextMenu', deepUpdate({ copyLoading: false, copyVisible: false }, state.contextMenu), state);
    }

    case actionTypes.CROSS_COPY_FAILURE: {
      return updateByKey('contextMenu', deepUpdate({ copyLoading: false }, state.contextMenu), state);
    }
    case actionTypes.ADD_UNDO_CONFIG: {
      const { list } = payload;
      // 新操作记录放在头部
      return {
        ...state,
        undoReducers: [list, ...state.undoReducers].slice(0, 5)
      };
    }
    case actionTypes.REMOVE_UNDO_CONFIG: {
      // 去掉最新的操作记录
      return { ...state, undoReducers: state.undoReducers.slice(1) };
    }
    case actionTypes.INIT_UNDO_LIST: {
      return { ...state, undoReducers: [] };
    }
    case actionTypes.FOCUS_LAYER_ADD:
      return { ...state, focusLayers: state.focusLayers.concat(payload) };
    case actionTypes.FOCUS_LAYER_DELETE:
      return { ...state, focusLayers: state.focusLayers.filter((id) => !~payload.indexOf(id)) };
    case 'FOCUS_LAYER_CLEAN':
      return { ...state, focusLayers: [] };
    case actionTypes.COMPONENT_CONFIG_ACTIVE_KEY_CHANGE:
      return { ...state, componentConfigActiveKey: payload.componentConfigActiveKey };
    case actionTypes.COMPONENT_EDIT_MODAL_SHOW: {
      return { ...state, modalEdit: payload.componentId };
    }
    case actionTypes.COMPONENT_EDIT_MODAL_HIDE: {
      return { ...state, modalEdit: null };
    }
    case actionTypes.OPEN_EDIT: {
      return { ...state, editId: payload.editId };
    }
    case actionTypes.CLOSE_EDIT: {
      return { ...state, editId: null };
    }
    default:
      return state;
  }
}
