import { combineReducers, PayloadAction } from '@reduxjs/toolkit';
import { ChartEditorProps } from 'app/components/ChartEditor';
import { BOARD_UNDO } from 'app/pages/DashBoardPage/constants';
import {
  BoardInfo,
  BoardLinkFilter,
  DeviceType,
  JumpPanel,
  WidgetData,
  WidgetErrorType,
  WidgetInfo,
  WidgetPanelParams,
} from 'app/pages/DashBoardPage/pages/Board/slice/types';
import { EditBoardState } from 'app/pages/DashBoardPage/pages/BoardEditor/slice/types';
import { getInitBoardInfo } from 'app/pages/DashBoardPage/utils/board';
import { PageInfo } from 'app/pages/MainPage/pages/ViewPage/slice/types';
import { Layout } from 'react-grid-layout';
/** { excludeAction,includeAction } */
import undoable, { includeAction } from 'redux-undo';
import { useInjectReducer } from 'utils/@reduxjs/injectReducer';
import { createSlice } from 'utils/@reduxjs/toolkit';
import { WidgetControllerPanelParams } from './../../Board/slice/types';
import { editBoardStackSlice } from './childSlice/stackSlice';
import {
  fetchEditBoardDetail,
  getEditChartWidgetDataAsync,
  getEditControllerOptions,
  toUpdateDashboard,
} from './thunk';

// BoardInfo
// editDashBoardInfoActions

const editDashBoardInfoSlice = createSlice({
  name: 'editBoard',
  initialState: getInitBoardInfo({
    id: 'default',
  }) as EditBoardState['boardInfo'],
  reducers: {
    initEditBoardInfo(state, action: PayloadAction<BoardInfo>) {
      const boardInfo = action.payload;
      Object.keys(boardInfo).forEach(key => {
        state[key] = boardInfo[key];
      });
    },
    clearEditBoardInfo(state) {
      const boardInfo = getInitBoardInfo({ id: 'default' });
      Object.keys(boardInfo).forEach(key => {
        state[key] = boardInfo[key];
      });
    },
    changeDashboardEdit(state, action: PayloadAction<boolean>) {
      state.editing = action.payload;
    },
    changeEditBoardLoading(state, action: PayloadAction<boolean>) {
      state.loading = action.payload;
    },
    changeFullScreenItem(state, action: PayloadAction<string>) {
      state.fullScreenItemId = action.payload;
    },
    changeControllerPanel(
      state,
      action: PayloadAction<WidgetControllerPanelParams>,
    ) {
      state.controllerPanel = action.payload;
    },
    changeLinkagePanel(state, action: PayloadAction<WidgetPanelParams>) {
      state.linkagePanel = action.payload;
    },
    changeJumpPanel(state, action: PayloadAction<JumpPanel>) {
      state.jumpPanel = action.payload;
    },
    adjustDashLayouts(state, action: PayloadAction<Layout[]>) {
      state.layouts = JSON.parse(JSON.stringify(action.payload));
      // state.layouts = [...action.payload];
    },
    changeShowBlockMask(state, action: PayloadAction<boolean>) {
      state.showBlockMask = action.payload;
    },
    changeBoardDroppable(state, action: PayloadAction<boolean>) {
      state.isDroppable = action.payload;
    },
    addClipboardWidgets(
      state,
      action: PayloadAction<BoardInfo['clipboardWidgets']>,
    ) {
      state.clipboardWidgets = action.payload;
    },
    clearClipboardWidgets(state) {
      state.clipboardWidgets = {};
    },
    changeChartEditorProps(
      state,
      action: PayloadAction<ChartEditorProps | undefined>,
    ) {
      state.chartEditorProps = action.payload;
    },

    changeBoardLinkFilter(
      state,
      action: PayloadAction<{
        boardId: string;
        triggerId: string;
        linkFilters?: BoardLinkFilter[];
      }>,
    ) {
      const { boardId, triggerId, linkFilters } = action.payload;
      state.linkFilter = state.linkFilter.filter(
        link => link.triggerWidgetId !== triggerId,
      );
      if (linkFilters) {
        state.linkFilter = state.linkFilter.concat(linkFilters);
      }
    },
    changeBoardDevice(state, action: PayloadAction<DeviceType>) {
      state.deviceType = action.payload;
    },
  },
  extraReducers: builder => {
    //  updateDashboard
    builder.addCase(toUpdateDashboard.pending, state => {
      state.saving = true;
    });
    builder.addCase(toUpdateDashboard.fulfilled, (state, action) => {
      state.saving = false;
    });
    builder.addCase(toUpdateDashboard.rejected, state => {
      state.saving = false;
    });
    //loadEditBoardDetail
    builder.addCase(fetchEditBoardDetail.pending, state => {
      state.loading = true;
    });
    builder.addCase(fetchEditBoardDetail.fulfilled, (state, action) => {
      state.loading = false;
    });
    builder.addCase(fetchEditBoardDetail.rejected, state => {
      state.loading = false;
    });
  },
});
// widgetInfo
// editWidgetInfoActions
const widgetInfoRecordSlice = createSlice({
  name: 'editBoard',
  initialState: {} as EditBoardState['widgetInfoRecord'],
  reducers: {
    selectWidget(
      state,
      action: PayloadAction<{
        multipleKey: boolean;
        id: string;
        selected: boolean;
      }>,
    ) {
      const { multipleKey, id, selected } = action.payload;
      if (multipleKey) {
        state[id].selected = selected;
      } else {
        for (let key of Object.keys(state)) {
          if (key === id) {
            state[id].selected = selected;
          } else {
            state[key].selected = false;
          }
        }
      }
    },
    selectSubWidget(state, action: PayloadAction<string>) {
      const id = action.payload;
      if (!state[id].selected) {
        for (let key of Object.keys(state)) {
          state[key].selected = false;
        }
        state[id].selected = true;
      }
    },
    renderedWidgets(state, action: PayloadAction<string[]>) {
      const ids = action.payload;
      ids.forEach(id => {
        state[id] && (state[id].rendered = true);
      });
    },
    clearSelectedWidgets(state) {
      for (let key of Object.keys(state)) {
        state[key].selected = false;
        state[key].editing = false;
      }
    },
    openWidgetEditing(state, action: PayloadAction<{ id: string }>) {
      const { id } = action.payload;
      for (let key of Object.keys(state)) {
        state[key].selected = false;
      }
      state[id].selected = true;
      state[id].editing = true;
    },
    closeWidgetEditing(state, action: PayloadAction<string>) {
      const id = action.payload;
      if (id) {
        state[id].selected = false;
        state[id].editing = false;
      } else {
        for (let key of Object.keys(state)) {
          state[key].selected = false;
          state[key].editing = false;
        }
      }
    },
    addWidgetInfos(state, action: PayloadAction<Record<string, WidgetInfo>>) {
      const widgetInfoMap = action.payload;
      const widgetIds = Object.keys(widgetInfoMap);
      widgetIds.forEach(id => {
        state[id] = widgetInfoMap[id];
      });
    },
    clearWidgetInfo(state) {
      Object.keys(state).forEach(id => {
        delete state[id];
      });
    },
    changeWidgetInLinking(
      state,
      action: PayloadAction<{
        boardId?: string;
        widgetId: string;
        toggle: boolean;
      }>,
    ) {
      const { widgetId, toggle } = action.payload;
      state[widgetId].inLinking = toggle;
    },
    changePageInfo(
      state,
      action: PayloadAction<{
        boardId?: string;
        widgetId: string;
        pageInfo: Partial<PageInfo> | undefined;
      }>,
    ) {
      const { widgetId, pageInfo } = action.payload;
      state[widgetId].pageInfo = pageInfo || { pageNo: 1 };
    },
    setWidgetErrInfo(
      state,
      action: PayloadAction<{
        boardId?: string;
        widgetId: string;
        errInfo?: string;
        errorType: WidgetErrorType;
      }>,
    ) {
      const { widgetId, errInfo, errorType } = action.payload;

      let WidgetRrrInfo = state?.[widgetId]?.errInfo;
      if (!WidgetRrrInfo) return;
      if (errInfo) {
        WidgetRrrInfo[errorType] = errInfo;
      } else {
        delete WidgetRrrInfo[errorType];
      }
    },
  },
  extraReducers: builder => {
    builder.addCase(getEditChartWidgetDataAsync.pending, (state, action) => {
      const { widgetId } = action.meta.arg;
      if (!state?.[widgetId]) return;
      state[widgetId].loading = true;
    });
    builder.addCase(getEditChartWidgetDataAsync.fulfilled, (state, action) => {
      const { widgetId } = action.meta.arg;
      if (!state?.[widgetId]) return;

      state[widgetId].loading = false;
    });
    builder.addCase(getEditChartWidgetDataAsync.rejected, (state, action) => {
      const { widgetId } = action.meta.arg;
      if (!state?.[widgetId]) return;
      state[widgetId].loading = false;
    });
    builder.addCase(getEditControllerOptions.pending, (state, action) => {
      const widgetId = action.meta.arg;
      if (!state?.[widgetId]) return;
      state[widgetId].loading = true;
    });
    builder.addCase(getEditControllerOptions.fulfilled, (state, action) => {
      const widgetId = action.meta.arg;
      if (!state?.[widgetId]) return;
      state[widgetId].loading = false;
    });
    builder.addCase(getEditControllerOptions.rejected, (state, action) => {
      const widgetId = action.meta.arg;
      if (!state?.[widgetId]) return;
      state[widgetId].loading = false;
    });
  },
});
const editWidgetDataSlice = createSlice({
  name: 'editBoard',
  initialState: {} as EditBoardState['widgetDataMap'],
  reducers: {
    setWidgetData(state, action: PayloadAction<WidgetData>) {
      const widgetData = action.payload;
      state[widgetData.id] = widgetData;
    },
  },
});
export const { actions: editBoardStackActions } = editBoardStackSlice;
export const { actions: editDashBoardInfoActions } = editDashBoardInfoSlice;
export const { actions: editWidgetInfoActions } = widgetInfoRecordSlice;
export const { actions: editWidgetDataActions } = editWidgetDataSlice;
const filterActions = [
  editBoardStackActions.setBoardToEditStack,
  editBoardStackActions.updateBoard,
  editBoardStackActions.toggleAllowOverlap,
  editBoardStackActions.updateBoardConfig,
  editBoardStackActions.addWidgets,
  editBoardStackActions.deleteWidgets,
  editBoardStackActions.changeAutoBoardWidgetsRect,
  editBoardStackActions.resizeWidgetEnd,

  editBoardStackActions.tabsWidgetAddTab,
  editBoardStackActions.tabsWidgetRemoveTab,
  editBoardStackActions.updateWidgetConfig,
  editBoardStackActions.updateWidgetsConfig,
  editBoardStackActions.changeWidgetsIndex,
  editBoardStackActions.changeBoardHasQueryControl,
  editBoardStackActions.changeBoardHasResetControl,

  editBoardStackActions.toggleLockWidget,
].map(ele => ele.toString());
const editBoardStackReducer = undoable(editBoardStackSlice.reducer, {
  undoType: BOARD_UNDO.undo,
  redoType: BOARD_UNDO.redo,
  ignoreInitialState: true,
  // filter: excludeAction([configActions.changeSlideEdit(false).type]),
  // 像 高频的 组件拖拽。resize、select虽然是用户的行为,但是也不能都记录在 快照中.只记录resizeEnd 和 dragEnd 有意义的结果快照
  filter: includeAction(filterActions),
});

const editBoardReducer = combineReducers({
  stack: editBoardStackReducer,
  boardInfo: editDashBoardInfoSlice.reducer,
  widgetInfoRecord: widgetInfoRecordSlice.reducer,
  widgetDataMap: editWidgetDataSlice.reducer,
});

export const useEditBoardSlice = () => {
  useInjectReducer({ key: 'editBoard', reducer: editBoardReducer });
};