import http from '@/utils/fetch';
import { api } from '@/constants/config';
import { actionTypes } from '@/constants/action-types';
import { getFirstSelectedId, insertLayerById, getGlobalLayers } from '@/utils/layer';
import { getScreenCenter, getTopScreenId } from '@/utils/screen';
import { getScreen } from './screen';
import { updateByKey, updateByKeyname, deepUpdate, deleteByKey } from '@/utils/data-helper';
import { addUndoConfig } from '@/models/create-app';
import { deepFind, isRefScreen, parseSearchParams, isEditPage } from '@/utils/utils';
import { getId } from '@/utils/interaction';
import { getFilters } from './filter';
import { setScreenResult } from '@/models/screen-detail';
import message from '@/components/message';
import { getDataContainers } from '@/models/data-container';
import cloneDeep from 'lodash/cloneDeep';
import { setPanelLimit } from '@/utils/panelLimit';
import { getPanelInfoByParams } from '@/services/panel';
import { request } from '@/utils/fetch';

/**
 * @description 编辑页获取引用面板
 * @param id 引用面板或动态面板ID
 * @param signal
 * @returns
 */
export function getPanelInfoForScreenEdit(id, signal?) {
  return async (dispatch, getState) => {
    const { panelsById, screenDetail, screenEdit } = getState();
    const { screenState } = screenEdit;
    const panel = panelsById[id];

    if (!panel) {
      let param: any = { id };
      const token = parseSearchParams()?._easyv_token;
      if (token) {
        param = {
          ...param,
          token: token,
        };
      }

      const result = await getPanelInfoByParams(
        {
          id,
        },
        undefined,
        undefined,
        undefined,
        param,
        { signal },
      );

      if (result) {
        const { name, config, screenId, type, states: _states, screenConfig = [] } = result;

        dispatch({
          type: actionTypes.PANEL_GET,
          payload: {
            id,
            name,
            config,
            screenId,
            states: _states,
            type,
            screenConfig,
          },
        });
        if (screenDetail.id === param.id) {
          dispatch(setScreenResult(result));
        }
        let states = cloneDeep(_states);
        if (!screenState) {
          // false - 非第一次，动态面板或者引用面板都只请求1个
          states = states.splice(0, 1);
        }
        if (type === 1) {
          // 引用面板
          await Promise.all(
            states.map((id) => {
              dispatch(getFilters(id));
              dispatch(getDataContainers(id));
            }),
          );
        }

       
        await Promise.all(states.map((id) => dispatch(getScreen(id))));
      }

      return result;
    } else {
      if (screenState === 1) {
        // 二轮
        const { type, states } = panel;
        // 如果第二轮应该跳过状态1
        if (type === 1) {
          // 引用面板
          await Promise.all(
            states.map((id, i) => {
              if (i) {
                dispatch(getFilters(id));
                dispatch(getDataContainers(id));
              }
            }),
          );
        }

        await Promise.all(states.map((id) => dispatch(getScreen(id))));
      }
      return panel;
    }
  };
}
/**
 * @description 预览页获取引用面板数据
 * @param id
 * @param signal
 * @returns
 */
export function getPanelInfoForScreenPreview(id, signal?) {
  return async (dispatch, getState) => {
    const { panelsById, screenDetail } = getState();

    const panel = panelsById[id];

    if (!panel) {
      let param: any = { id };
      const token = parseSearchParams()?._easyv_token;
      if (token) {
        param = {
          ...param,
          token: token,
        };
      }

      const result = await getPanelInfoByParams(param, undefined, undefined, { signal }, param, {
        signal,
      });

      if (result) {
        const { name, config, screenId, states, type, screenConfig = [] } = result;
        dispatch({
          type: actionTypes.PANEL_GET,
          payload: {
            id,
            name,
            config,
            screenId,
            states,
            type,
            screenConfig,
          },
        });
        if (screenDetail.id === param.id) {
          await dispatch(setScreenResult(result));
        }
      }

      return result;
    } else {
      return panel;
    }
  };
}

// 添加动态/引用面板
export function addPanel(type = 0) {
  return async (dispatch, getState) => {
    const { createApp, screensById, user } = getState();
    const { id: screenId, scale, layersSelected } = createApp;
    const { layers } = screensById[screenId];

    if (
      setPanelLimit(
        type === 1 ? 'referencePanelCountLimit' : 'dynamicPanelCountLimit',
        user,
        layers,
      )
    ) {
      message.error(type === 1 ? '引用面板数已经到达上限' : '动态面板数已经到达上限');
      return;
    }

    const layerName = type === 1 ? '引用面板' : '动态面板';
    const hide = message.loading(`正在添加${layerName}...`, 0);
    const { left, top } = getScreenCenter(scale);
    const firstSelectedId = layersSelected.length
      ? getFirstSelectedId({ layers, selected: layersSelected })
      : undefined;

    interface Resulf {
      id: number | string;
      name: string;
      config: any;
      states: Array<any>;
    }

    const result: any = await http.post<Resulf>(api.panelAdd, {
      id: screenId,
      insertId: firstSelectedId,
      sceneCenterPoint: [left, top],
      type: type,
    });

    hide();
    if (result) {
      dispatch({
        type: actionTypes.PANEL_ADD,
        payload: {
          id: result.id,
          name: result.name,
          config: result.config,
          screenId: screenId,
          states: result.states,
          type,
          screenConfig: [],
        },
      });

      const layerId = `${type === 1 ? 'ref' : 'panel'}_${result.id}`;

      if (result.states.length) {
        // 加载默认屏
        dispatch(getScreen(result.states[0]));
      }

      // 更新图层
      const newLayers = insertLayerById({
        layers,
        layer: {
          id: layerId,
          name: layerName,
          show: true,
          lock: false,
        },
        insertId: firstSelectedId,
      });

      dispatch({
        type: actionTypes.LAYER_UPDATE,
        payload: {
          id: screenId,
          layers: newLayers,
        },
      });

      // 选择添加的动态面板
      dispatch({
        type: actionTypes.LAYER_SELECT,
        payload: {
          selected: [layerId],
        },
      });
    }
    return result;
  };
}

// 更新动态面板配置
export function updatePanel(list) {
  return async (dispatch, getState) => {
    const { panelsById } = getState();
    if (!Array.isArray(list)) {
      list = [list];
    }

    const oldStates = list.map(({ id }) => ({
      ...panelsById[id],
      id: panelsById[id].type === 1 ? `ref_${id}` : `panel_${id}`,
    }));
    const newStates = list.map(({ id, updateData }) => deepUpdate(updateData, panelsById[id]));

    dispatch({
      type: actionTypes.PANEL_UPDATE,
      payload: { list: newStates },
    });

    dispatch(addUndoConfig({ list: oldStates }));

    return await http.post(api.panelUpdate, {
      configs: newStates.map((item) => ({
        id: item.id,
        config: JSON.stringify(item.config),
        states: item.states,
      })),
    });
  };
}

// 动态面板添加状态
export function addState() {
  return async (dispatch, getState) => {
    const { createApp, screensById, user, panelsById } = getState();
    const { id } = createApp;
    const screen = screensById[id];
    const { panelId } = screen;

    const { states } = panelsById[panelId];
    if (setPanelLimit('dynamicPanelStateLimit', user, states)) {
      message.error('单个动态面板的状态数已经到达上限');
      return;
    }

    interface Resulf {
      id: number | string;
      name: string;
      config: any;
      layers: Array<any>;
      leftBarWidth: any;
      thumb: any;
      lines: any;
      filters: any;
      panelId: number;
    }
    const result: any = await http.post<Resulf>(api.panelStateAdd, { id: panelId });

    if (result) {
      const { id, name, config, layers, leftBarWidth, thumb, lines, filters, panelId } = result;

      dispatch({
        type: actionTypes.PANEL_STATE_ADD,
        payload: {
          id: id,
          name: name,
          config: config,
          layers,
          leftBarWidth,
          thumb,
          lines,
          filters,
          panelId,
        },
      });

      return result;
    }
  };
}

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

    const result = await http.post(api.panelStateDelete, { id });

    if (result) {
      dispatch({
        type: actionTypes.PANEL_STATE_DELETE,
        payload: {
          panelId,
          stateId: id,
        },
      });
      return result;
    }
  };
}

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

    const { panelsById } = getState();
    const panel = panelsById[id];
    const { states } = panel;
    const source = states[oldIndex];
    const target = states[newIndex];
    const clonedStates = states.slice();
    clonedStates.splice(oldIndex, 1);
    clonedStates.splice(newIndex, 0, source);

    dispatch({
      type: actionTypes.PANEL_STATE_SORT,
      payload: {
        panelId: id,
        states: clonedStates,
      },
    });

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

    if (!result) {
      dispatch({
        type: actionTypes.PANEL_STATE_SORT,
        payload: {
          panelId: id,
          states: states,
        },
      });
    }
  };
}

export function copyState(id) {
  return async (dispatch, getState) => {
    const hide = message.loading('正在复制状态...', 0);
    interface Resulf {
      id: number | string;
    }
    const result: any = await http.post(api.panelStateCopy, { id });
    hide();

    if (result) {
      const { screensById } = getState();
      const screen = screensById[id];

      dispatch({
        type: actionTypes.PANEL_STATE_COPY,
        payload: {
          id: result.id,
          panelId: screen.panelId,
        },
      });

      await dispatch(getScreen(result.id));

      return result;
    }
  };
}

export function beforeScreenLink(linkedScreenId) {
  return async (dispatch, getState) => {
    const result = await dispatch(getScreen(linkedScreenId));
    if (result) {
      const { screensById, panelsById } = getState();
      const linkedScreenLayer = getGlobalLayers({ entry: linkedScreenId, screensById, panelsById });

      const linkedScreens: any = [];
      deepFind(
        linkedScreenLayer,
        (item) => {
          if (isRefScreen(item.id)) {
            const panelId: any = getId(item.id);
            const panel = panelsById[panelId];
            if (panel) {
              linkedScreens.push(...panel.states);
            }
          }
          return false;
        },
        'components',
      );

      if (linkedScreens.length === 0) {
        return true;
      }

      const topScreenId = getTopScreenId();

      if (linkedScreens.includes(topScreenId)) {
        return false;
      }

      for (let i = 0; i < linkedScreens.length; i++) {
        const result = await dispatch(beforeScreenLink(linkedScreens[i]));
        if (!result) {
          return false;
        }
      }

      return true;
    }
  };
}

export const updatePanelInfoByPanelId = (panelId: number) => {
  return async (dispatch) => {
    const result = await request(api.panelGet, { id: panelId });
    if (result) {
      const { name, config, screenId, type, states: _states, screenConfig = [] } = result;
      dispatch({
        type: actionTypes.PANEL_GET,
        payload: {
          id: panelId,
          name,
          config,
          screenId,
          states: _states,
          type,
          screenConfig,
        },
      });
    }
  };
};

const initialState = {};

export default function panelReducer(state = initialState, { type, payload }) {
  switch (type) {
    case actionTypes.PANEL_GET: {
      return updateByKey(payload.id, payload, state);
    }

    case actionTypes.PANEL_ADD: {
      return {
        ...state,
        [payload.id]: payload,
      };
    }

    case actionTypes.PANEL_COPY: {
      const panels = payload.reduce((all, item) => ({ ...all, [item.id]: item }), {});

      return {
        ...state,
        ...panels,
      };
    }

    case actionTypes.PANEL_UPDATE: {
      return updateByKeyname('id', payload.list, state);
    }

    case actionTypes.HYBRID_UPDATE: {
      const { panels } = payload;
      if (!panels.length) return state;
      return updateByKeyname('id', panels, state);
    }

    case actionTypes.PANEL_STATE_ADD: {
      return {
        ...state,
        [payload.panelId]: {
          ...state[payload.panelId],
          states: state[payload.panelId].states.concat(payload.id),
        },
      };
    }

    case actionTypes.PANEL_STATE_DELETE: {
      const { panelId, stateId } = payload;
      return {
        ...state,
        [panelId]: {
          ...state[panelId],
          states: state[panelId].states.filter((d) => d != stateId),
        },
      };
    }

    case actionTypes.PANEL_STATE_SORT: {
      return {
        ...state,
        [payload.panelId]: {
          ...state[payload.panelId],
          states: payload.states,
        },
      };
    }

    case actionTypes.PANEL_DELETE: {
      const { list } = payload;
      return deleteByKey(list, state);
    }

    case actionTypes.PANEL_STATE_COPY: {
      return {
        ...state,
        [payload.panelId]: {
          ...state[payload.panelId],
          states: state[payload.panelId].states.concat(payload.id),
        },
      };
    }

    case actionTypes.CLEAR: {
      return {};
    }

    default:
      return state;
  }
}
