/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
  getIsIMPAKTProductMode,
} from "@/redux/config/configSelector"
import { getActionList } from "@/redux/currentApp/action/actionSelector"
import { Events } from "@/redux/currentApp/action/actionState"
import { executionActions } from "@/redux/currentApp/executionTree/executionSlice"

import { transformDataFormat } from "@/utils/action/transformDataFormat"
import { IMPAKTAPPSEditorRuntimePropsCollectorInstance } from "@/utils/executionTreeHelper/runtimePropsCollector"
import { runAllEventHandler } from "./runActionEventHandler"
import { runTransformer } from "./runActionTransformer"
import { transResponse } from "./transResponse"
import { ActionContent, ActionItem, ActionType } from "@/redux/currentApp/action/interface"
import { RestAPIAction, RestAPIBodyContent } from "@/page/App/components/PublicTypes/action/restApi"
import { isIMPAKTAPPSAPiError } from "@/page/App/components/PublicTypes/ResourceGenerator"
import axios from "axios"
import { buildAxiosConfig } from "@/page/App/components/Actions/axiosConfigBuilder"
import { isEmpty } from "lodash"
// import { NavigateFunction } from "react-router-dom"
import { error } from "console"
import { Page } from "@/lib"

const checkCanSendRequest = (
  _actionType: ActionType,
  _actionContent: ActionContent,
) => {
  return true;
};
export const fetchActionRunResult = async (
  _appID: string,
  _actionID: string,
  data: any,
  _isPublic: boolean,
  _abortSignal?: AbortSignal,
  actionType?: ActionType
) => {
  const config = buildAxiosConfig(data, actionType);
  // const token = JSON.parse(window.localStorage.getItem("token"));
  const body = isEmpty(config?.body) ? {
    headers: {
      // 'Authorization': `Bearer ${token}`,
      ...config?.headers
    }
  } : config?.body
  try {
    const data = await axios[actionType === "impaktapps" ? "post" : config.method](
      config.url,
      body,
      {
        headers: {
          // 'Authorization': `Bearer ${token}`,
          ...config?.headers
        }
      }
    );
    return data;
  } catch (err) {
    return err;
  }

};
export const fetchCommonActionResult = async (
  isPublic: boolean,
  resourceID: string,
  actionType: ActionType,
  displayName: string,
  appId: string,
  actionID: string,
  actionContent: ActionContent,
  actionContext: Record<string, unknown> = {},
  ruleRef?: Page,
  abortSignal?: AbortSignal,

) => {
  const canSendRequest = checkCanSendRequest(actionType, actionContent)
  if (!canSendRequest) {
    return Promise.reject(false)
  }

  const requestBody = {
    resourceID,
    actionType,
    displayName,
    ruleRef,
    content: actionContent,
    context: actionContext,
  }
  return await fetchActionRunResult(
    appId,
    actionID,
    requestBody,
    isPublic,
    abortSignal,
    actionType
  )

};

export const fetchActionResult = async (
  actionType: ActionType,
  isProductionMode: boolean,
  isPublic: boolean,
  resourceID: string,
  displayName: string,
  appId: string,
  currentActionId: string,
  actionContent: ActionContent,
  $context: Record<string, unknown>,
  abortSignal: AbortSignal | undefined,
  ruleRef: Page
) => {

  const response: any = await fetchCommonActionResult(
    !isProductionMode ? false : isPublic,
    (resourceID as string) || "",
    actionType as ActionType,
    displayName,
    appId,
    currentActionId,
    actionContent,
    $context,
    ruleRef,
    abortSignal,
  )
  return transResponse(actionType, actionContent, response)
}

export interface IExecutionActions extends ActionItem<ActionContent> {
  $actionID: string
  $resourceID: string
  $context: Record<string, unknown>
}

export const runActionWithExecutionResult = async (
  action: IExecutionActions,
  needRunEventHandler: boolean = true, store: any,
  // navigate?: NavigateFunction,
  navigate?: any,
  abortSignal?: AbortSignal,

) => {
  const { displayName } = action as ActionItem<RestAPIAction<RestAPIBodyContent>>
  const {
    content,
    $actionID,
    $resourceID,
    actionType,
    transformer,
    $context,
    config,
  } = action
  const originActionList = getActionList(store.getState())
  const originAction = originActionList.find(
    (item) => item.displayName === displayName,
  )
  if (!content || !originAction) return Promise.reject(false)
  const rootState = store.getState()
  const isProductionMode = getIsIMPAKTProductMode(rootState)
  const {
    successEvent: _successEvent = [],
    failedEvent: _failedEvent = [],
    ...restContent
  } = content as ActionContent & Events

  const mockConfig = config.mockConfig!
  const {
    successEvent: originSuccessEvent = [],
    failedEvent: originFailedEvent = [],
    $dynamicAttrPaths = [],
  } = originAction.content as ActionContent &
  Events & { $dynamicAttrPaths: string[] }
  const actionContent = transformDataFormat(
    actionType as ActionType,
    restContent,
  ) as ActionContent

  store.dispatch(
    executionActions.updateExecutionByDisplayNameReducer({
      displayName: displayName,
      value: {
        isRunning: true,
        startTime: new Date().getTime(),
        endTime: new Date().getTime(),
      },
    }),
  )

  const currentActionId = $actionID as string

  try {
    let IMPAKTAPPSInnerTransformedResponse

    const mockEnabled = isProductionMode
      ? mockConfig?.enabled && mockConfig?.enableForReleasedApp
      : mockConfig?.enabled

    if (mockEnabled) {
      IMPAKTAPPSInnerTransformedResponse = {
        data: mockConfig.mockData,
      }
    } else {
      IMPAKTAPPSInnerTransformedResponse = await fetchActionResult(
        actionType,
        isProductionMode,
        config?.public ?? false,
        ($resourceID as string) || "",
        displayName,
        "",
        currentActionId,
        actionContent,
        $context,
        abortSignal,
        action.ruleRef
      )
    }

    const userTransformedData = runTransformer(
      transformer,
      IMPAKTAPPSInnerTransformedResponse.data ?? "", store
    )
    store.dispatch(
      executionActions.updateExecutionByDisplayNameReducer({
        displayName: displayName,
        value: {
          // ...IMPAKTAPPSInnerTransformedResponse,
          data: userTransformedData,
          runResult: userTransformedData ? { error: false } : { error: true, message: IMPAKTAPPSInnerTransformedResponse?.response?.errorMessage },
          isRunning: false,
          endTime: new Date().getTime(),
        },
      }),
    )

    if (needRunEventHandler) {
      runAllEventHandler(originSuccessEvent, $dynamicAttrPaths, store, navigate)
    }
    return userTransformedData ? Promise.resolve(userTransformedData) : Promise.reject("Apifail")
  } catch (e) {
    const runResult = {
      error: true,
      message: "An unknown error",
    }
    if (isIMPAKTAPPSAPiError(e)) {
      runResult.message = e.data?.errorMessage || "An unknown error"
      try {
        if (e.data?.errorMessage.startsWith("run action error: ")) {
          const arr = e.data?.errorMessage.split("run action error: ")
          if (arr.length > 1) {
            const error = JSON.parse(arr[1])
            const errResponse = {
              ...e,
              data: error,
            }
          }
        }
      } catch (e) { console.log(e) }
    }

    store.dispatch(
      executionActions.updateExecutionByDisplayNameReducer({
        displayName: displayName,
        value: {
          data: undefined,
          runResult: runResult,
          isRunning: false,
          endTime: new Date().getTime(),
        },
      }),
    )
    if (needRunEventHandler)
      runAllEventHandler(originFailedEvent, $dynamicAttrPaths, store, navigate)

    return Promise.reject(runResult)
  }
}

export const runOriginAction = async (action: ActionItem<ActionContent>, store, navigate) => {
  const { displayName } = action
  const finalContext =
    IMPAKTAPPSEditorRuntimePropsCollectorInstance.getGlobalCalcContext({}, store)
  const realAction = (finalContext as Record<string, unknown>)[
    displayName
  ] as IExecutionActions
  return await runActionWithExecutionResult(realAction, true, store, navigate)
}

export const runActionWithDelay = (
  action: IExecutionActions, store,
  abortSignal?: AbortSignal,

) => {
  const { config } = action
  if (!config || !config.advancedConfig) {
    runActionWithExecutionResult(action, true, store, () => { }, abortSignal)
    return
  }
  const { advancedConfig } = config
  const { delayWhenLoaded } = advancedConfig
  return new Promise((resolve, reject) => {
    const timeoutID = window.setTimeout(
      async () => {
        window.clearTimeout(timeoutID)

        try {
          const result = await runActionWithExecutionResult(
            action,
            true,
            store,
            () => { },
            abortSignal,
          )
          return resolve(result)
        } catch (e) {
          console.log("e", e)
          return reject(e)
        }
      },
      delayWhenLoaded as unknown as number,
    )
  })
}

const actionIDMapTimerID: Record<string, number> = {}
export const registerActionPeriod = (action: IExecutionActions) => {
  const { config } = action
  if (
    !config ||
    !config.advancedConfig ||
    !config.advancedConfig.isPeriodically ||
    (config.advancedConfig.periodInterval as unknown as number) <= 0
  ) {
    removeActionPeriod(action.$actionID)
    return
  }
  removeActionPeriod(action.$actionID)
  const timeID = window.setInterval(
    () => {
      // runActionWithExecutionResult(action)
    },
    (config.advancedConfig.periodInterval as unknown as number) * 1000,
  )
  actionIDMapTimerID[action.$actionID] = timeID
}

export const removeActionPeriod = (actionID: string) => {
  if (actionIDMapTimerID[actionID]) {
    window.clearInterval(actionIDMapTimerID[actionID])
  }
}

export const removeAllActionPeriod = () => {
  Object.values(actionIDMapTimerID).forEach((id) => {
    window.clearInterval(id)
  })
}
