/* eslint-disable @typescript-eslint/no-explicit-any */
import { Unsubscribe, } from "@reduxjs/toolkit"
import { configActions } from "@/redux/config/configSlice"
import {
  getComponentMap,
  getGlobalDataToActionList,
  searchComponentFromMap,
} from "@/redux/currentApp/components/componentsSelector"
import { componentsActions } from "@/redux/currentApp/components/componentsSlice"
import { getExecutionResult } from "@/redux/currentApp/executionTree/executionSelector"
import { executionActions } from "@/redux/currentApp/executionTree/executionSlice"
import { AppListenerEffectAPI, AppStartListening } from "@/store"
import { mixedChangeDisplayNameHelper } from "@/utils/changeDisplayNameHelper"
import { CONTAINER_TYPE } from "./componentsState"


export enum REDUX_ACTION_FROM {
  UNDO = "undo",
  REDO = "redo",
  WS = "ws",
}

function handleUpdateComponentDisplayNameEffect(
  action: ReturnType<
    typeof componentsActions.updateComponentDisplayNameReducer
  >,
  listenApi: AppListenerEffectAPI,
) {
  const { newDisplayName } = action.payload
  const rootState = listenApi.getState()
  const components = getComponentMap(rootState)
  const newComponent = searchComponentFromMap(components, newDisplayName)
  if (
    newComponent &&
    newComponent.containerType === CONTAINER_TYPE.EDITOR_SCALE_SQUARE
  ) {
    listenApi.dispatch(
      configActions.updateSelectedComponent([newComponent.displayName]),
    )
  }
}

async function handleChangeCurrentPageWhenDelete(
  action: ReturnType<typeof componentsActions.deletePageNodeReducer>,
  listenerApi: AppListenerEffectAPI,
) {
  const rootState = listenerApi.getState()
  const executionTree = getExecutionResult(rootState)
  const rootNode = executionTree.root
  const { currentPageIndex, homepageDisplayName, pageSortedKey } = rootNode
  const { displayName, originPageSortedKey } = action.payload
  const newSortedKey = originPageSortedKey.filter((key) => key !== displayName)
  const currentPageDisplayName = originPageSortedKey[currentPageIndex]
  if (displayName === homepageDisplayName) {
    if (currentPageDisplayName === homepageDisplayName) {
      listenerApi.dispatch(
        componentsActions.updateRootNodePropsReducer({
          currentPageIndex: 0,
          homepageDisplayName: pageSortedKey[0],
          pageSortedKey,
        }),
      )
    } else {
      listenerApi.dispatch(
        componentsActions.updateRootNodePropsReducer({
          currentPageIndex: 0,
          homepageDisplayName: pageSortedKey[0],
          pageSortedKey,
        }),
      )
      setTimeout(() => {
        const newIndex = pageSortedKey.findIndex(
          (key: string) => key === currentPageDisplayName,
        )
        const currentIndex = newIndex === -1 ? 0 : newIndex
        listenerApi.dispatch(
          executionActions.updateExecutionByDisplayNameReducer({
            displayName: "root",
            value: {
              currentPageIndex: currentIndex,
            },
          }),
        )
      })
    }
  } else {
    const newIndex = pageSortedKey.findIndex(
      (key: string) => key === currentPageDisplayName,
    )
    listenerApi.dispatch(
      executionActions.updateExecutionByDisplayNameReducer({
        displayName: "root",
        value: {
          currentPageIndex: newIndex === -1 ? 0 : newIndex,
          pageSortedKey: newSortedKey,
        },
      }),
    )
  }
}

async function handleChangeCurrentSectionWhenDelete(
  action: ReturnType<typeof componentsActions.deleteSectionViewReducer>,
  listenerApi: AppListenerEffectAPI,
) {
  const { viewDisplayName, originPageSortedKey, parentNodeName } =
    action.payload
  const rootState = listenerApi.getState()
  const executionTree = getExecutionResult(rootState)
  const parentNode = executionTree[parentNodeName]
  if (!parentNode) return
  const oldIndex = originPageSortedKey.findIndex(
    (key) => key === viewDisplayName,
  )
  if (oldIndex === parentNode.currentViewIndex) {
    listenerApi.dispatch(
      executionActions.updateExecutionByDisplayNameReducer({
        displayName: parentNodeName,
        value: {
          currentViewIndex: 0,
        },
      }),
    )
  }
}

const handleUpdateGlobalDataDisplayNameEffect = (
  action: ReturnType<typeof componentsActions.setGlobalStateReducer>,
  listenerApi: AppListenerEffectAPI,
) => {
  const { key, oldKey } = action.payload
  if (!oldKey) return
  const rootState = listenerApi.getState()
  const globalDataList = getGlobalDataToActionList(rootState)
  const currentGlobalData = globalDataList.find(
    (action) => action.displayName === key,
  )
  if (!currentGlobalData) return
  listenerApi.dispatch(configActions.changeSelectedAction(currentGlobalData))
  mixedChangeDisplayNameHelper(listenerApi, oldKey, key, "globalDataKey")
}


const updateSubPagePathEffect = (
  action: ReturnType<typeof componentsActions.updateSubPagePathReducer>,
  listenApi: AppListenerEffectAPI,
) => {
  const { pageName, subPagePath, oldSubPagePath } = action.payload
  const oldExecutionResult = getExecutionResult(listenApi.getState())
  const rootNode = oldExecutionResult.root
  mixedChangeDisplayNameHelper(listenApi, oldSubPagePath, subPagePath)
  if (rootNode.currentSubPagePath === oldSubPagePath) {
    listenApi.dispatch(
      executionActions.updateCurrentPagePathReducer({
        pageDisplayName: pageName,
        subPagePath,
      }),
    )
  }
}

const handleDeleteSubPageViewNodeEffect = (
  action: ReturnType<typeof componentsActions.deleteSubPageViewNodeReducer>,
  listenApi: AppListenerEffectAPI,
) => {
  const { pageName, subPagePath } = action.payload
  const oldExecutionResult = getExecutionResult(listenApi.getState())
  const rootNode = oldExecutionResult.root
  if (rootNode.currentSubPagePath === subPagePath) {
    listenApi.dispatch(
      executionActions.updateCurrentPagePathReducer({
        pageDisplayName: pageName,
        subPagePath: undefined,
      }),
    )
  }
}

export function setupComponentsListeners(
  startListening: AppStartListening,
): Unsubscribe {
  const subscriptions = [
    startListening({
      actionCreator: componentsActions.updateComponentDisplayNameReducer,
      effect: handleUpdateComponentDisplayNameEffect,
    }),
    startListening({
      actionCreator: componentsActions.deletePageNodeReducer,
      effect: handleChangeCurrentPageWhenDelete,
    }),
    startListening({
      actionCreator: componentsActions.deleteSectionViewReducer,
      effect: handleChangeCurrentSectionWhenDelete,
    }),
    startListening({
      actionCreator: componentsActions.setGlobalStateReducer,
      effect: handleUpdateGlobalDataDisplayNameEffect,
    }),
    startListening({
      actionCreator: componentsActions.updateSubPagePathReducer,
      effect: updateSubPagePathEffect,
    }),
    startListening({
      actionCreator: componentsActions.deleteSubPageViewNodeReducer,
      effect: handleDeleteSubPageViewNodeEffect,
    })
  ]

  return () => {
    subscriptions.forEach((unsubscribe) => unsubscribe())
  }
}
