import { AnyAction } from "@reduxjs/toolkit"
import { REDUX_ACTION_FROM } from "@/middleware/undoRedo/interface"

import { RootState } from "@/store"
import IMPAKTAPPSUndoRedoManager from "@/utils/undoRedo/undo"
import { ComponentMapNode } from "@/redux/currentApp/components/componentsState"
import { getCanvas, searchDSLByDisplayName } from "@/redux/currentApp/components/componentsSelector"

export const componentsSnapShot = (
  reduxAction: string,
  action: AnyAction,
  _prevRootState: RootState,
  _nextRootState: RootState,
) => {
  switch (reduxAction) {
    // COMPONENT
    case "addComponentReducer": {
      const newAction = {
        type: "components/deleteComponentNodeReducer",
        payload: {
          displayNames: action.payload.map(
            (item: ComponentMapNode) => item.displayName,
          ),
          source: "undoRedo",
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "deleteComponentNodeReducer": {
      const originActionComponentNode = action.payload.displayNames
        .map((displayName: string) => {
          return searchDSLByDisplayName(displayName, _prevRootState)
        })
        .filter((item: ComponentMapNode | null) => item != undefined)
      const newAction = {
        type: "components/addComponentReducer",
        payload: originActionComponentNode,
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "addModalComponentReducer": {
      const newAction = {
        type: "components/deleteComponentNodeReducer",
        payload: {
          displayNames: [action.payload.modalComponentNode.displayName],
          source: "undoRedo",
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "updateComponentLayoutInfoReducer": {
      const originActionComponentNode = searchDSLByDisplayName(
        action.payload.displayName,
        _prevRootState,
      )
      if (!originActionComponentNode) break
      const newAction = {
        type: "components/updateComponentLayoutInfoReducer",
        payload: {
          displayName: action.payload.displayName,
          layoutInfo: {
            x: originActionComponentNode.x,
            y: originActionComponentNode.y,
            w: originActionComponentNode.w,
            h: originActionComponentNode.h,
          },
          parentNode: originActionComponentNode.parentNode,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "updateComponentContainerReducer": {
      const originNodeLayoutInfos = (
        action.payload 
      ).updateSlices
        .map((item) => {
          return searchDSLByDisplayName(item.displayName, _prevRootState)
        })
        .filter((item) => item !== null) as ComponentMapNode[]
      const newUpdateSlices = originNodeLayoutInfos.map((item) => {
        return {
          displayName: item.displayName,
          x: item.x,
          y: item.y,
          w: item.w,
          h: item.h,
        }
      })
      const newAction = {
        type: "components/updateComponentContainerReducer",
        payload: {
          oldParentNodeDisplayName: action.payload.newParentNodeDisplayName,
          newParentNodeDisplayName: action.payload.oldParentNodeDisplayName,
          updateSlices: newUpdateSlices,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "updateComponentDisplayNameReducer": {
      const { displayName, newDisplayName } = action.payload

      const newAction = {
        type: "components/updateComponentDisplayNameReducer",
        payload: {
          displayName: newDisplayName,
          newDisplayName: displayName,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "setComponentPropsReducer":
    case "updateComponentPropsReducer": {
      const { displayName, notUseUndoRedo } = action.payload
      if (notUseUndoRedo) break
      const originNode = searchDSLByDisplayName(displayName, _prevRootState)
      if (!originNode) break
      const newAction = {
        type: "components/setComponentPropsReducer",
        payload: {
          displayName,
          updateSlice: originNode.props,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    // PAGE
    case "addTargetPageSectionReducer": {
      const { pageName, addedSectionName } = action.payload
      const newAction = {
        type: "components/deleteTargetPageSectionReducer",
        payload: {
          pageName,
          deleteSectionName: addedSectionName,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "deleteTargetPageSectionReducer": {
      const { pageName, deleteSectionName } = action.payload

      const currentTargeNode = searchDSLByDisplayName(pageName, _prevRootState)
      if (!currentTargeNode) break
      const originSectionNode = currentTargeNode.childrenNode.find(
        (node:any) => node.showName === deleteSectionName,
      )
      if (!originSectionNode) break

      const newAction = {
        type: "components/addTargetPageSectionReducer",
        payload: {
          pageName,
          addedSectionName: deleteSectionName,
          originSectionNode,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "addSectionViewReducer": {
      const { parentNodeName } = action.payload

      const originParentNode = searchDSLByDisplayName(
        parentNodeName,
        _nextRootState,
      )
      if (!originParentNode) break
      const { props } = originParentNode
      if (!props) break
      const { viewSortedKey } = props
      if (!Array.isArray(viewSortedKey)) break

      const lastViewSortedKey = (viewSortedKey as string[]).at(-1)
      if (!lastViewSortedKey) break
      const newAction = {
        type: "components/deleteSectionViewReducer",
        payload: {
          viewDisplayName: lastViewSortedKey,
          parentNodeName,
          originPageSortedKey: viewSortedKey,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "deleteSectionViewReducer": {
      const { parentNodeName, viewDisplayName } = action.payload
      const originParentNode = searchDSLByDisplayName(
        parentNodeName,
        _prevRootState,
      )

      if (!originParentNode) break

      const viewNode:any = originParentNode.childrenNode.find(
        (node:any) => node.displayName === viewDisplayName,
      )
      if (!viewNode) break
      const originChildrenNode = viewNode.childrenNode

      const newAction = {
        type: "components/addSectionViewReducer",
        payload: {
          parentNodeName,
          sectionName: originParentNode.showName,
          originChildrenNode: originChildrenNode,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "updateTargetPagePropsReducer": {
      const { pageName, notUseUndoRedo } = action.payload
      if (notUseUndoRedo) break
      const originPage = searchDSLByDisplayName(pageName, _prevRootState)
      if (!originPage) break
      const newAction = {
        type: "components/updateTargetPagePropsReducer",
        payload: {
          pageName,
          newProps: originPage.props,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "addPageNodeWithSortOrderReducer": {
      const { displayName } = action.payload
      const rootNode:any = getCanvas(_nextRootState)
      if (!rootNode || !rootNode.props) break

      const newAction = {
        type: "components/deletePageNodeReducer",
        payload: {
          displayName: displayName,
          originPageSortedKey: rootNode.props.pageSortedKey,
        },
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "deletePageNodeReducer": {
      const originPageNode = searchDSLByDisplayName(
        action.payload.displayName,
        _prevRootState,
      )
      if (!originPageNode) break
      const newAction = {
        type: "components/addPageNodeWithSortOrderReducer",
        payload: originPageNode,
        from: action.from,
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
    case "updateTargetPageLayoutReducer": {
      const { pageName } = action.payload
      const originPageNode = searchDSLByDisplayName(pageName, _prevRootState)
      if (!originPageNode || !originPageNode.props) break
      const newAction = {
        type: "components/updateTargetPageLayoutReducer",
        payload: {
          pageName: pageName,
          layout: originPageNode.props.layout,
          originPageNode,
        },
      }
      if (action.from === REDUX_ACTION_FROM.UNDO) {
        IMPAKTAPPSUndoRedoManager.pushToRedoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      } else {
        IMPAKTAPPSUndoRedoManager.pushToUndoStack([
          JSON.parse(JSON.stringify(newAction)),
        ])
      }
      break
    }
  }
}
