import message from 'components/message';
import http, { request } from 'utils/fetch';
import { api } from 'constants/config';
import { actionTypes } from 'constants/action-types';
import { getPanelInfoForScreenEdit } from 'models/panel';
import { addOfficialResources } from 'models/material-lib';
import {
  toObject,
  isOrder,
  getFirstSelectedId,
  getGroupChildren,
  getPanelsFromLayers,
} from 'utils/layer';
import { getScreenCenter, getTopScreenId } from 'utils/screen';
import { componentOperator, getComponentDimension, transformComponents } from 'utils/component';
import { uploadAssets } from 'utils/upload';
import { isGeneralPanel, isComponent, isGroup } from 'utils/utils';
import { getId } from 'utils/interaction';
import { commponentsAdd } from './component';

export function getModules(type = 2) {
  return async (dispatch) => {
    dispatch({
      type: actionTypes.MODULE_GET_LIST_START,
    });
    const categorys = await request(api.officialCategory, undefined, {
      type,
    });
    // const modules = dispatch(getModuleLIst({}));
    if (categorys) {
      dispatch({
        type: actionTypes.MODULE_GET_LIST_SUCCESS,
        payload: {
          categorys,
        },
      });
    } else {
      dispatch({
        type: actionTypes.MODULE_GET_LIST_FAILURE,
      });
    }
  };
}

export function getModuleLIst({
  pageNum = 1,
  pageSize = 10,
  name = '',
}: {
  pageNum?: number;
  pageSize?: number;
  name?: string;
}) {
  return async (dispatch, getState) => {
    const param = {
      pageNum,
      pageSize,
    };
    const result = await request(
      api.getAllLayerMaterial,
      undefined,
      name ? Object.assign(param, { name }) : param,
    );
    if (result) {
      dispatch({
        type: actionTypes.MODULE_GET_LIST_SUCCESS,
        payload: {
          list: result.data,
        },
      });
    } else {
      dispatch({
        type: actionTypes.MODULE_GET_LIST_FAILURE,
      });
    }
    return result;
  };
}

export function createModule({
  name,
  recommended,
  platformCategoryId,
  preview,
  edition,
  thumb,
  officialCategoryId,
  labels,
  price,
  needPaid
}) {
  return async (dispatch, getState) => {
    const { createApp, componentsById, screensById, panelsById } = getState();
    const { id, layersSelected } = createApp;
    const { layers } = screensById[id];
    const layersById = toObject(layers);

    let thumbPath = thumb;
    if (typeof thumb === 'object') {
      const result = await uploadAssets({
        path: `thumb/${thumb.name}`,
        file: thumb,
      });
      if (!result) {
        return;
      }
      thumbPath = result;
    }
    let previewPath = thumb;
    if (typeof preview === 'object') {
      const result = await uploadAssets({
        path: `thumb/${preview.name}`,
        file: preview,
      });
      if (!result) {
        return;
      }
      previewPath = result;
    }
    const moduleLayers = layersSelected.map((d) => layersById[d]);
    moduleLayers.sort((a, b) => (isOrder(a.path, b.path) ? -1 : 1));
    const componentsId: any = [];
    const panelsId: any = [];
    const sperateIds = (ids) => {
      ids.forEach((d) => {
        if (isComponent(d)) {
          componentsId.push(d);
        } else if (isGeneralPanel(d)) {
          panelsId.push(getId(d));
        } else if (isGroup(d)) {
          const children = getGroupChildren(layersById[d]).map((o) => o.id);
          sperateIds(children);
        }
      });
    };
    sperateIds(layersSelected);

    const childrenId: any = [];
    const componentsDimension = componentsId.reduce((all, item) => {
      const component = componentsById[item];
      if (component) {
        const dimension = getComponentDimension(component.config);
        const children = componentOperator.getChildren(component.id, componentsById);
        if (children && children.length) {
          childrenId.push(...children.map((d) => d.id));
        }
        all.push(dimension);
      }
      return all;
    }, []);
    const panelsDimension = panelsId.map((d) => {
      const panel = panelsById[d];
      const { config } = panel;
      const { width, height, top, left } = config;

      return { width, height, left, top };
    });
    const selectedDimensions = componentsDimension.concat(panelsDimension);
    const minLeft = Math.min(...selectedDimensions.map((d) => d.left));
    const maxRight = Math.max(...selectedDimensions.map((d) => d.left + d.width));
    const minTop = Math.min(...selectedDimensions.map((d) => d.top));
    const maxBottom = Math.max(...selectedDimensions.map((d) => d.top + d.height));
    const centerPoint = [
      Math.round((minLeft + maxRight) / 2),
      Math.round((minTop + maxBottom) / 2),
    ];

    const params = {
      name,
      thumb: thumbPath ? thumbPath : '',
      officialCategoryId,
      platformCategoryId,
      preview: previewPath,
      edition,
      recommended: recommended ? true : false,
      layers: moduleLayers.map((d) => ({ ...d, path: undefined, groupPath: undefined })),
      components: componentsId,
      children: childrenId,
      panels: panelsId,
      labels: labels,
      centerPoint,
      needPaid,
      price
    }
    const result = await dispatch(
      addOfficialResources(params),
    );

    if (result) {
      dispatch({
        type: actionTypes.MODULE_CREATE_SUCCESS,
        payload: result,
      });
      message.success('保存成功');
      return result;
    }
  };
}

export function addModule(moduleId) {
  return async (dispatch, getState) => {
    const { createApp, screensById } = getState();
    const { id, scale, layersSelected } = createApp;
    const { layers } = screensById[id];

    const { left, top } = getScreenCenter(scale);
    const firstSelectedId = layersSelected.length
      ? getFirstSelectedId({ layers, selected: layersSelected })
      : undefined;

    const result: any = await http.post(api.moduleAdd, {
      id,
      moduleId,
      centerPoint: [left, top],
      insertId: firstSelectedId,
    });

    if (result) {
      // 如果行业模块中添加的组件，可能带有过滤器，需要添加
      if (result.filters && result.filters.length) {
        const topScreenId = getTopScreenId();
        dispatch({
          type: actionTypes.FILTER_ADD,
          payload: {
            filter: result.filters.map((d) => ({ ...d, screenId: topScreenId })),
          },
        });
      }

      // 追加components
      const addedComponentsById = transformComponents(result.components, id);
      // dispatch({
      //   type: actionTypes.COMPONENTS_ADD,
      //   payload: {
      //     list: Object.keys(addedComponentsById).map((d) => addedComponentsById[d])
      //   }
      // });
      dispatch(
        commponentsAdd({
          list: Object.keys(addedComponentsById).map((d) => addedComponentsById[d]),
        }),
      );

      // 如果存在动态面板
      const panels = getPanelsFromLayers(result.layers);
      if (panels.length) {
        panels.map((d) => dispatch(getPanelInfoForScreenEdit(getId(d.id))));
      }

      // 更新layers
      dispatch({
        type: actionTypes.LAYER_UPDATE,
        payload: {
          id,
          layers: result.layers,
        },
      });

      // 选中添加的layer
      dispatch({
        type: actionTypes.LAYER_SELECT,
        payload: {
          selected: [result.selectedLayerId || result.layers[0].id],
        },
      });
    }
  };
}

export function deleteModules(ids) {
  return async (dispatch) => {
    dispatch({
      type: actionTypes.MODULE_LOADING,
      payload: true,
    });
    const result = await http.post(api.moduleDelete, {
      ids,
    });
    if (result) {
      dispatch(getModules());
    }

    dispatch({
      type: actionTypes.MODULE_LOADING,
      payload: false,
    });
  };
}

export function publishModules(param) {
  return async (dispatch) => {
    dispatch({
      type: actionTypes.MODULE_LOADING,
      payload: true,
    });
    const result = await http.post(api.modulePublish, param);
    if (result) {
      dispatch(getModules());
    }

    dispatch({
      type: actionTypes.MODULE_LOADING,
      payload: false,
    });
  };
}

export function updateModule({ id, name, category, thumb, published }) {
  return async (dispatch) => {
    let thumbPath = thumb;
    if (typeof thumb === 'object') {
      const result = await uploadAssets({
        path: `thumb/${thumb.name}`,
        file: thumb,
      });
      if (!result) {
        return;
      }
      thumbPath = result;
    }

    const result = await http.post(api.moduleUpdate, {
      id,
      name,
      thumb: thumbPath ? thumbPath : '',
      categoryId: category,
      published,
    });

    if (result) {
      dispatch(getModules());
      return result;
    }
  };
}

export function sortModules(orders) {
  return async (dispatch) => {
    const orderKeys = Object.keys(orders);
    if (orderKeys.length) {
      const orderArr = orderKeys.map((d) => ({
        name: `module_category_${d}`,
        list: orders[d].map((d) => d.id),
      }));
      const result = await http.post(api.moduleSort, orderArr);
      if (result) {
        dispatch(getModules());
        return result;
      }
    }
  };
}

export function exportModules(ids) {
  return async () => {
    const result = await http.post(api.moduleExport, { ids });
    if (result) {
      return result;
    }
  };
}

export function importModules(data, signal) {
  return async () => {
    const result: any = await http.post(
      api.moduleImport,
      {
        modulesConfig: JSON.parse(data.modulesConfig),
        categoryConfig: JSON.parse(data.categoryConfig),
      },
      { signal },
    );
    if (Array.isArray(result) && result[0] && result[1]) {
      return result;
    }
  };
}

export function getCategorys() {
  return async (dispatch) => {
    const result = await http.get(api.moduleCategoryList);
    if (result) {
      dispatch({
        type: actionTypes.MODULE_CATEGORY_GET_LIST_SUCCESS,
        payload: result,
      });
    }
  };
}

export function addCategory(name) {
  return async (dispatch) => {
    const result = await http.post(api.moduleCategoryCreate, { name });
    if (result) {
      dispatch({
        type: actionTypes.MODULE_CATEGORY_CREATE_SUCCESS,
        payload: result,
      });
    }
  };
}

export function updateCategory({ id, name }) {
  return async (dispatch) => {
    const result = await http.post(api.moduleCategoryUpdate, { id, name });
    if (result) {
      dispatch({
        type: actionTypes.MODULE_CATEGORY_UPDATE_SUCCESS,
        payload: {
          id,
          name,
        },
      });
    }
  };
}

export function deleteCategory(id) {
  return async (dispatch) => {
    const result = await http.post(api.moduleCategoryDelete, { id });
    if (result) {
      dispatch({
        type: actionTypes.MODULE_CATEGORY_DELETE_SUCCESS,
        payload: {
          id,
        },
      });
    }
  };
}

export function sortCategory({ oldIndex, newIndex }) {
  return async (dispatch, getState) => {
    if (oldIndex === newIndex) {
      return;
    }

    const { modules } = getState();
    const { categorys } = modules;
    const source = categorys[oldIndex + 1];
    const target = categorys[newIndex + 1];
    const clonedCategorys = categorys.slice();
    clonedCategorys.splice(oldIndex + 1, 1);
    clonedCategorys.splice(newIndex + 1, 0, source);
    dispatch({
      type: actionTypes.MODULE_CATEGORY_SORT_SUCCESS,
      payload: clonedCategorys,
    });

    const result = await http.post(api.moduleCategorySort, {
      origin: source.id,
      target: target.id,
    });

    if (!result) {
      dispatch({
        type: actionTypes.MODULE_CATEGORY_SORT_SUCCESS,
        payload: categorys,
      });
    }
  };
}

const initialState = {
  loading: false,
  list: [],
  categorys: [],
};

export default function reducers(state = initialState, { type, payload }) {
  switch (type) {
    case actionTypes.MODULE_GET_LIST_START: {
      return { ...state, loading: true };
    }
    case actionTypes.MODULE_GET_LIST_SUCCESS: {
      return { ...state, loading: false, ...payload };
    }
    case actionTypes.MODULE_GET_LIST_FAILURE: {
      return { ...state, loading: false };
    }
    case actionTypes.MODULE_CREATE_SUCCESS: {
      const newList = state.list.concat(payload);
      return { ...state, list: newList };
    }
    case actionTypes.MODULE_LOADING: {
      return { ...state, loading: payload };
    }

    case actionTypes.MODULE_CATEGORY_GET_LIST_SUCCESS: {
      return { ...state, categorys: payload };
    }
    case actionTypes.MODULE_CATEGORY_CREATE_SUCCESS: {
      const newCategorys = state.categorys.concat(payload);
      return { ...state, categorys: newCategorys };
    }
    case actionTypes.MODULE_CATEGORY_DELETE_SUCCESS: {
      const newCategorys = state.categorys.filter((d: any) => d.id !== payload.id);
      return { ...state, categorys: newCategorys };
    }
    case actionTypes.MODULE_CATEGORY_UPDATE_SUCCESS: {
      const newCategorys = state.categorys.map((d: any) =>
        d.id === payload ? { ...d, name: payload.name } : d,
      );
      return { ...state, categorys: newCategorys };
    }
    case actionTypes.MODULE_CATEGORY_SORT_SUCCESS: {
      return { ...state, categorys: payload };
    }
    default:
      return state;
  }
}
