import log from "@racletteCore/lib/logger"
import { $api, $store } from "@racletteCore"
import {
  removeCacheAttributes,
  capitalize,
  handleErrors,
} from "@racletteCore/lib/dataHelper"
import handleServerItem from "./responseTypeHandler"
import { handleOperationTarget } from "@racletteCore/setup/plugin-system"

const createAxiosConfig = (appRequestCode, pluginItemRequestConfig) => {
  const config = {
    headers: {
      "app-request-code": appRequestCode,
    },
  }
  const channels = []
  if (pluginItemRequestConfig.broadcast) {
    channels.push("data")
  }
  if (pluginItemRequestConfig?.channels?.length) {
    pluginItemRequestConfig.channels.forEach((channelConf) => {
      channels.push(channelConf.channel)
    })
  }

  if (channels?.length) {
    config.headers["app-broadcast-channels"] = channels
  }
  return config
}

const storeActions = {
  dataMove: (actionId, payload) => {
    const newParent = payload.item.newParent
    const oldParent = payload.item.oldParent
    $store.dispatch({
      type: "data/move",
      docId: payload.item._id,
      docType: payload.type,
      payload: { newParent, oldParent },
    })
  },
  dataCreate: (actionId, payload) => {
    $store.dispatch({
      type: "data/create",
      payload: {
        type: payload.type,
        actionId,
        item: payload.item,
      },
    })
  },
  dataUpdate: (actionId, payload) => {
    $store.dispatch({
      type: "data/update",
      docId: payload.item._id,
      payload: payload.item,
    })
  },
  dataDelete: (actionId, payload) => {
    $store.dispatch({
      type: "data/delete",
      payload: { type: payload.type, docId: payload.item._id },
    })
  },
  dataHardDelete: (actionId, payload) => {
    $store.dispatch({
      type: "data/hardDelete",
      payload: [payload.item._id],
    })
  },
}
const getAxiosPromise = async (method, target, source, config) => {
  if (method === "delete") {
    const deleteConfig =
      source != null ? { ...config, data: source } : config
    return await $api.axios.delete(target, deleteConfig)
  }
  return await $api.axios[method](target, source, config)
}
const writeData = async (actionId, operationDefinition, item, options) => {
  const type = operationDefinition.dataTypeName
  const cleanItem = removeCacheAttributes(item)
  log.api("writeData", cleanItem, { ...operationDefinition })
  const appRequestCode =
    operationDefinition.storeActionType ||
    `data${capitalize(operationDefinition.method)}`
  if (options.useStore !== false) {
    if (storeActions[appRequestCode]) {
      // execute store action
      storeActions[appRequestCode](actionId, {
        type,
        item: cleanItem,
      })
    } else {
      log.api(
        "writeData no valid storeAction Provided",
        storeActions,
        appRequestCode,
      )
    }
  }

  const validTarget = handleOperationTarget(operationDefinition.target, item)
  const config = createAxiosConfig(appRequestCode, operationDefinition)
  const notify = options.notify === false ? false : true

  if (options.useStore === false) {
    if (options.responseType === "stream") {
      return $api.fetch[operationDefinition.method](
        validTarget,
        cleanItem,
        config,
      )
    }
    return await getAxiosPromise(
      operationDefinition.method,
      validTarget,
      cleanItem,
      config,
    )
      .then((res) => {
        return {
          response: res,
        }
      })
      .catch(handleErrors)
  } else {
    return await getAxiosPromise(
      operationDefinition.method,
      validTarget,
      cleanItem,
      config,
    )
      .then((res) => {
        return {
          response: res,
          result: handleServerItem(res.data, notify, true),
        }
      })
      .catch(handleErrors)
  }
}

export default writeData
