/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

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 runtime_config_exports = {};
__export(runtime_config_exports, {
  APPROVAL_SINGLETON_ACTION_USES: () => APPROVAL_SINGLETON_ACTION_USES,
  APPROVAL_SURFACE_ROOT_USES: () => APPROVAL_SURFACE_ROOT_USES,
  FlowSurfaceApprovalRuntimeConfigService: () => FlowSurfaceApprovalRuntimeConfigService
});
module.exports = __toCommonJS(runtime_config_exports);
var import_lodash = __toESM(require("lodash"));
var import_service_utils = require("../service-utils");
var import_errors = require("../errors");
const APPROVAL_SURFACE_ROOT_USES = /* @__PURE__ */ new Set([
  "TriggerChildPageModel",
  "ApprovalChildPageModel",
  "ApplyTaskCardDetailsModel",
  "ApprovalTaskCardDetailsModel"
]);
const APPROVAL_SINGLETON_ACTION_USES = /* @__PURE__ */ new Set([
  "ApplyFormSubmitModel",
  "ApplyFormSaveDraftModel",
  "ApplyFormWithdrawModel",
  "ProcessFormApproveModel",
  "ProcessFormRejectModel",
  "ProcessFormReturnModel",
  "ProcessFormDelegateModel",
  "ProcessFormAddAssigneeModel"
]);
const APPROVAL_PROCESS_ACTION_STATUS_BY_USE = {
  ProcessFormApproveModel: 2,
  ProcessFormRejectModel: -1,
  ProcessFormReturnModel: 1,
  ProcessFormDelegateModel: 8,
  ProcessFormAddAssigneeModel: 99
};
const APPROVAL_PROCESS_ACTION_STATUS_ORDER = [2, -1, 1, 8, 99];
class FlowSurfaceApprovalRuntimeConfigService {
  constructor(deps) {
    this.deps = deps;
  }
  getRepositoryIfAvailable(resourceName) {
    try {
      return this.deps.db.getRepository(resourceName);
    } catch {
      return null;
    }
  }
  readModelField(model, fieldName) {
    var _a;
    return ((_a = model == null ? void 0 : model.get) == null ? void 0 : _a.call(model, fieldName)) ?? (model == null ? void 0 : model[fieldName]);
  }
  readApprovalConfig(model) {
    return import_lodash.default.cloneDeep(this.readModelField(model, "config") || {});
  }
  collectApprovalActionNodes(node, carry = []) {
    if (!(node == null ? void 0 : node.uid)) {
      return carry;
    }
    if (APPROVAL_SINGLETON_ACTION_USES.has(node.use || "")) {
      carry.push(node);
    }
    Object.values(node.subModels || {}).forEach((subModel) => {
      import_lodash.default.castArray(subModel).forEach((child) => this.collectApprovalActionNodes(child, carry));
    });
    return carry;
  }
  async findApprovalSurfaceRootForNode(uid, transaction) {
    let cursor = String(uid || "").trim();
    const visited = /* @__PURE__ */ new Set();
    while (cursor && !visited.has(cursor)) {
      visited.add(cursor);
      const node = await this.deps.repository.findModelById(cursor, {
        transaction,
        includeAsyncNode: true
      });
      if (!(node == null ? void 0 : node.uid)) {
        return null;
      }
      if (APPROVAL_SURFACE_ROOT_USES.has(node.use || "")) {
        return node;
      }
      cursor = String(
        node.parentId || await this.deps.locator.findParentUid(node.uid, transaction).catch(() => "") || ""
      );
    }
    return null;
  }
  async findApprovalWorkflowBySurfaceRootUid(rootUid, transaction) {
    const workflowsRepository = this.getRepositoryIfAvailable("workflows");
    if (!workflowsRepository) {
      return null;
    }
    const workflows = await workflowsRepository.find({
      filter: {
        type: "approval"
      },
      transaction
    });
    return workflows.find((workflow) => this.readApprovalConfig(workflow).approvalUid === rootUid) || null;
  }
  async findApprovalNodeBySurfaceRootUid(rootUid, transaction) {
    const nodesRepository = this.getRepositoryIfAvailable("flow_nodes");
    if (!nodesRepository) {
      return null;
    }
    const nodes = await nodesRepository.find({
      filter: {
        type: "approval"
      },
      transaction
    });
    return nodes.find((node) => this.readApprovalConfig(node).approvalUid === rootUid) || null;
  }
  async patchApprovalRuntimeConfig(resourceName, model, nextConfig, transaction) {
    const currentConfig = this.readApprovalConfig(model);
    if (import_lodash.default.isEqual(currentConfig, nextConfig)) {
      return;
    }
    await this.deps.db.getRepository(resourceName).update({
      filterByTk: this.readModelField(model, "id"),
      values: {
        config: nextConfig
      },
      transaction
    });
  }
  getApprovalActionStepValue(actionNode, fieldName) {
    const clickSettings = import_lodash.default.get(actionNode, ["stepParams", "clickSettings"]);
    return import_lodash.default.get(clickSettings, ["saveResource", fieldName]) ?? import_lodash.default.get(clickSettings, fieldName);
  }
  buildApprovalReturnRuntimeConfig(actionNode) {
    const settings = this.getApprovalActionStepValue(actionNode, "approvalReturnNodeSettings") || {};
    const type = String((settings == null ? void 0 : settings.type) || "start").trim();
    if (type === "any") {
      return {
        returnTo: -1,
        returnToNodeVariable: null
      };
    }
    if (type === "count") {
      const count = Number(settings == null ? void 0 : settings.count);
      return {
        returnTo: Number.isFinite(count) && count > 0 ? count : 1,
        returnToNodeVariable: null
      };
    }
    if (type === "specific") {
      const target = String((settings == null ? void 0 : settings.target) || "").trim();
      return {
        returnTo: target || null,
        returnToNodeVariable: target ? `{{$jobsMapByNodeKey.${target}}}` : null
      };
    }
    return {
      returnTo: null,
      returnToNodeVariable: null
    };
  }
  buildApprovalReassignRuntimeConfig(actionNode) {
    const assigneesScope = this.getApprovalActionStepValue(actionNode, "assigneesScope") || {};
    const assignees = import_lodash.default.castArray((assigneesScope == null ? void 0 : assigneesScope.assignees) || []).filter((item) => !import_lodash.default.isUndefined(item) && !import_lodash.default.isNull(item) && item !== "").map(
      (item) => import_lodash.default.isPlainObject(item) && !Object.prototype.hasOwnProperty.call(item, "filter") ? { filter: item } : item
    );
    return {
      assignees,
      options: (0, import_service_utils.buildDefinedPayload)({
        extraFieldKey: assigneesScope == null ? void 0 : assigneesScope.extraFieldKey
      })
    };
  }
  async syncApprovalWorkflowRuntimeConfig(root, transaction) {
    const workflow = await this.findApprovalWorkflowBySurfaceRootUid(root.uid, transaction);
    if (!workflow) {
      return;
    }
    const currentConfig = this.readApprovalConfig(workflow);
    const actions = this.collectApprovalActionNodes(root);
    await this.patchApprovalRuntimeConfig(
      "workflows",
      workflow,
      {
        ...currentConfig,
        withdrawable: actions.some((action) => action.use === "ApplyFormWithdrawModel")
      },
      transaction
    );
  }
  async syncApprovalNodeRuntimeConfig(root, transaction) {
    const node = await this.findApprovalNodeBySurfaceRootUid(root.uid, transaction);
    if (!node) {
      return;
    }
    const currentConfig = this.readApprovalConfig(node);
    const actionNodes = this.collectApprovalActionNodes(root);
    const statusSet = new Set(
      actionNodes.map((action) => APPROVAL_PROCESS_ACTION_STATUS_BY_USE[action.use || ""]).filter((status) => !import_lodash.default.isUndefined(status))
    );
    const nextConfig = {
      ...currentConfig,
      actions: APPROVAL_PROCESS_ACTION_STATUS_ORDER.filter((status) => statusSet.has(status))
    };
    const returnAction = actionNodes.find((action) => action.use === "ProcessFormReturnModel");
    Object.assign(
      nextConfig,
      returnAction ? this.buildApprovalReturnRuntimeConfig(returnAction) : {
        returnTo: null,
        returnToNodeVariable: null
      }
    );
    const delegateAction = actionNodes.find((action) => action.use === "ProcessFormDelegateModel");
    const delegateConfig = delegateAction ? this.buildApprovalReassignRuntimeConfig(delegateAction) : null;
    nextConfig.toDelegateReassignees = (delegateConfig == null ? void 0 : delegateConfig.assignees) || [];
    nextConfig.toDelegateReassigneesOptions = (delegateConfig == null ? void 0 : delegateConfig.options) || {};
    const addAssigneeAction = actionNodes.find((action) => action.use === "ProcessFormAddAssigneeModel");
    const addAssigneeConfig = addAssigneeAction ? this.buildApprovalReassignRuntimeConfig(addAssigneeAction) : null;
    nextConfig.toAddReassignees = (addAssigneeConfig == null ? void 0 : addAssigneeConfig.assignees) || [];
    nextConfig.toAddReassigneesOptions = (addAssigneeConfig == null ? void 0 : addAssigneeConfig.options) || {};
    await this.patchApprovalRuntimeConfig("flow_nodes", node, nextConfig, transaction);
  }
  async syncApprovalRuntimeConfigForSurfaceRoot(root, transaction) {
    if (!(root == null ? void 0 : root.uid)) {
      return;
    }
    const currentRoot = await this.deps.repository.findModelById(root.uid, {
      transaction,
      includeAsyncNode: true
    });
    if (!(currentRoot == null ? void 0 : currentRoot.uid)) {
      return;
    }
    if (currentRoot.use === "TriggerChildPageModel") {
      await this.syncApprovalWorkflowRuntimeConfig(currentRoot, transaction);
      return;
    }
    if (currentRoot.use === "ApprovalChildPageModel") {
      await this.syncApprovalNodeRuntimeConfig(currentRoot, transaction);
    }
  }
  async syncApprovalRuntimeConfigForNode(uid, transaction) {
    const root = await this.findApprovalSurfaceRootForNode(uid, transaction);
    if (root) {
      await this.syncApprovalRuntimeConfigForSurfaceRoot(root, transaction);
    }
  }
  async assertApprovalActionSingleton(parentUid, actionUse, transaction) {
    var _a;
    if (!APPROVAL_SINGLETON_ACTION_USES.has(actionUse)) {
      return;
    }
    const parent = await this.deps.repository.findModelById(parentUid, {
      transaction,
      includeAsyncNode: true
    });
    const existing = import_lodash.default.castArray(((_a = parent == null ? void 0 : parent.subModels) == null ? void 0 : _a.actions) || []).find((action) => (action == null ? void 0 : action.use) === actionUse);
    if (existing == null ? void 0 : existing.uid) {
      (0, import_errors.throwBadRequest)(`flowSurfaces addAction approval action '${actionUse}' already exists in '${parent.use}'`);
    }
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  APPROVAL_SINGLETON_ACTION_USES,
  APPROVAL_SURFACE_ROOT_USES,
  FlowSurfaceApprovalRuntimeConfigService
});
