var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var CustomActionTrigger_exports = {};
__export(CustomActionTrigger_exports, {
  OmniTrigger: () => OmniTrigger
});
module.exports = __toCommonJS(CustomActionTrigger_exports);
var import_module_error_handler = __toESM(require("@tachybase/module-error-handler"));
var import_server = require("@tego/server");
var import_lodash = __toESM(require("lodash"));
var import_constants = require("../../constants");
var import_triggers = __toESM(require("../../triggers"));
var import_utils = require("../../utils");
class CustomActionInterceptionError extends Error {
  constructor(message) {
    super(message);
    this.status = 400;
    this.messages = [];
    this.name = "CustomActionInterceptionError";
  }
}
const _OmniTrigger = class _OmniTrigger extends import_triggers.default {
  constructor(workflow) {
    super(workflow);
    this.triggerAction = async (context, next) => {
      const {
        params: { filterByTk, values, triggerWorkflows = "", filter, resourceName, actionName }
      } = context.action;
      if (actionName !== "trigger" || resourceName === "workflows") {
        return next();
      }
      const { currentUser, currentRole } = context.state;
      const { model: UserModel } = this.workflow.db.getCollection("users");
      const userInfo = {
        user: UserModel.build(currentUser).desensitize(),
        roleName: currentRole
      };
      const dataSourceHeader = context.get("x-data-source");
      const jointCollectionName = (0, import_server.joinCollectionName)(dataSourceHeader, resourceName);
      const triggerWorkflowsMap = /* @__PURE__ */ new Map();
      const triggerWorkflowsArray = [];
      for (const trigger of triggerWorkflows.split(",")) {
        const [key, path] = trigger.split("!");
        triggerWorkflowsMap.set(key, path);
        triggerWorkflowsArray.push(key);
      }
      const workflows = Array.from(this.workflow.enabledCache.values()).filter(
        (item) => item.type === _OmniTrigger.TYPE && item.config.collection === jointCollectionName && triggerWorkflowsArray.includes(item.key)
      ).sort((a, b) => {
        const aIndex = triggerWorkflowsArray.indexOf(a.key);
        const bIndex = triggerWorkflowsArray.indexOf(b.key);
        if (aIndex === -1 && bIndex === -1) {
          return a.id - b.id;
        }
        if (aIndex === -1) {
          return 1;
        }
        if (bIndex === -1) {
          return -1;
        }
        return aIndex - bIndex;
      });
      const syncGroup = [];
      const asyncGroup = [];
      for (const workflow of workflows) {
        const { appends = [] } = workflow.config;
        const [dataSourceName, collectionName] = (0, import_server.parseCollectionName)(workflow.config.collection);
        const dataPath = triggerWorkflowsMap.get(workflow.key);
        const event = [workflow];
        const { repository } = context.app.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
        const formData = dataPath ? import_lodash.default.get(values, dataPath) : values;
        let data = formData;
        if (filterByTk != null) {
          if ((0, import_lodash.isArray)(filterByTk)) {
            data = await repository.find({ filterByTk, appends });
          } else {
            data = await repository.findOne({ filterByTk, appends });
          }
          if (!data) {
            continue;
          }
          Object.assign(data, formData);
        } else if (filter != null) {
          data = await repository.find({ filter, appends });
          if (!data) {
            continue;
          }
          Object.assign(data, formData);
        }
        event.push({ data: (0, import_utils.toJSON)(data), ...userInfo });
        (workflow.sync ? syncGroup : asyncGroup).push(event);
      }
      for (const event of syncGroup) {
        const processor = await this.workflow.trigger(event[0], event[1], { httpContext: context });
        if (!processor) {
          return context.throw(500);
        }
        const { lastSavedJob, nodesMap } = processor;
        const lastNode = nodesMap.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
        if (processor.execution.status === import_constants.EXECUTION_STATUS.RESOLVED) {
          if ((lastNode == null ? void 0 : lastNode.type) === "end") {
            return;
          }
          continue;
        }
        if (processor.execution.status < import_constants.EXECUTION_STATUS.STARTED) {
          if ((lastNode == null ? void 0 : lastNode.type) !== "end") {
            return context.throw(
              500,
              context.t("Workflow on your action failed, please contact the administrator", { ns: "workflow" })
            );
          }
          const err = new CustomActionInterceptionError("Request is intercepted by workflow");
          err.status = 400;
          err.messages = context.state.messages;
          return context.throw(err.status, err);
        }
        return context.throw(500, "Workflow on your action hangs, please contact the administrator");
      }
      for (const event of asyncGroup) {
        this.workflow.trigger(event[0], event[1]);
      }
      await next();
    };
    this.middleware = async (context, next) => {
      const {
        resourceName,
        actionName,
        params: { triggerWorkflows, beforeWorkflows }
      } = context.action;
      if (beforeWorkflows) {
        await this.trigger(context, beforeWorkflows, "before");
      }
      if (resourceName === "workflows" && actionName === "trigger") {
        return this.triggerAction(context, next);
      }
      await next();
      if (!triggerWorkflows) {
        return;
      }
      if (!["create", "update"].includes(actionName)) {
        return;
      }
      return this.trigger(context, triggerWorkflows);
    };
    this.workflow.app.resourcer.registerActionHandler("trigger", this.triggerAction);
    this.workflow.app.acl.allow("*", "trigger", "loggedIn");
    this.workflow.app.pm.get(import_module_error_handler.default).errorHandler.register(
      (err) => err instanceof CustomActionInterceptionError,
      async (err, ctx) => {
        ctx.body = {
          errors: err.messages
        };
        ctx.status = err.status;
      }
    );
    workflow.app.resourcer.use(this.middleware, { tag: "workflowTrigger", after: "acl" });
  }
  async trigger(context, workflowList, order = "after") {
    if (!workflowList) {
      return;
    }
    const { values } = context.action.params;
    const dataSourceHeader = context.get("x-data-source") || "main";
    const { currentUser, currentRole } = context.state;
    const { model: UserModel } = this.workflow.db.getCollection("users");
    const userInfo = {
      user: UserModel.build(currentUser).desensitize(),
      roleName: currentRole
    };
    const triggers = workflowList.split(",").map((trigger) => trigger.split("!"));
    const workflowRepo = this.workflow.db.getRepository("workflows");
    const workflows = (await workflowRepo.find({
      filter: {
        key: triggers.map((trigger) => trigger[0]),
        current: true,
        type: "general-action",
        enabled: true
      }
    })).filter((workflow) => Boolean(workflow.config.collection));
    const syncGroup = [];
    const asyncGroup = [];
    for (const workflow of workflows) {
      const { collection, appends = [] } = workflow.config;
      const [dataSourceName, collectionName] = (0, import_server.parseCollectionName)(collection);
      const trigger = triggers.find((trigger2) => trigger2[0] === workflow.key);
      const event = [workflow];
      if (context.action.resourceName !== "workflows") {
        if (order === "before") {
          event.push({ data: context.action.params, ...userInfo });
          (workflow.sync ? syncGroup : asyncGroup).push(event);
          continue;
        }
        if (!context.body) {
          continue;
        }
        if (dataSourceName !== dataSourceHeader) {
          continue;
        }
        const { body: data } = context;
        for (const row of Array.isArray(data) ? data : [data]) {
          let payload = row;
          if (trigger[1]) {
            const paths = trigger[1].split(".");
            for (const field of paths) {
              if (payload.get(field)) {
                payload = payload.get(field);
              } else {
                const association = (0, import_server.modelAssociationByKey)(payload, field);
                payload = await payload[association.accessors.get]();
              }
            }
          }
          const model = payload.constructor;
          if (payload instanceof import_server.Model) {
            if (collectionName !== model.collection.name) {
              continue;
            }
            if (appends.length) {
              payload = await model.collection.repository.findOne({
                filterByTk: payload.get(model.primaryKeyAttribute),
                appends
              });
            }
          }
          event.push({ data: (0, import_utils.toJSON)(payload), ...userInfo });
        }
      } else {
        const { model, repository } = context.app.dataSourceManager.dataSources.get(dataSourceName).collectionManager.getCollection(collectionName);
        let data = trigger[1] ? (0, import_lodash.get)(values, trigger[1]) : values;
        const pk = (0, import_lodash.get)(data, model.primaryKeyAttribute);
        if (appends.length && pk != null) {
          data = await repository.findOne({
            filterByTk: pk,
            appends
          });
        }
        event.push({ data, ...userInfo });
      }
      (workflow.sync ? syncGroup : asyncGroup).push(event);
    }
    for (const event of syncGroup) {
      await this.workflow.trigger(event[0], event[1], { httpContext: context });
    }
    for (const event of asyncGroup) {
      this.workflow.trigger(event[0], event[1]);
    }
  }
  on() {
  }
  off() {
  }
};
_OmniTrigger.TYPE = "general-action";
let OmniTrigger = _OmniTrigger;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  OmniTrigger
});
