/**
 * 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 __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var utils_exports = {};
__export(utils_exports, {
  abortExecution: () => abortExecution,
  getExecutionLockKey: () => getExecutionLockKey,
  getExecutionStatusName: () => getExecutionStatusName,
  getJobLockKey: () => getJobLockKey,
  getWorkflowExecutionLogMeta: () => getWorkflowExecutionLogMeta,
  isLockAcquireError: () => isLockAcquireError,
  toJSON: () => toJSON,
  validateCollectionField: () => validateCollectionField
});
module.exports = __toCommonJS(utils_exports);
var import_database = require("@nocobase/database");
var import_data_source_manager = require("@nocobase/data-source-manager");
var import_constants = require("./constants");
function getExecutionLockKey(executionId) {
  return `workflow:execution:${executionId}`;
}
function getJobLockKey(jobId) {
  return `workflow:job:${jobId}`;
}
function isLockAcquireError(error) {
  return error instanceof Error && error.constructor.name === "LockAcquireError";
}
function afterTransactionCommit(transaction, callback) {
  if (typeof transaction.afterCommit === "function") {
    transaction.afterCommit(callback);
    return;
  }
  callback();
}
function validateCollectionField(collection, dataSourceManager) {
  const [dataSourceName, collectionName] = (0, import_data_source_manager.parseCollectionName)(collection);
  if (!dataSourceName || !collectionName) {
    return { collection: `"collection" must be in the format "dataSourceName:collectionName"` };
  }
  const dataSource = dataSourceManager.dataSources.get(dataSourceName);
  if (!dataSource) {
    return { collection: `Data source "${dataSourceName}" does not exist` };
  }
  if (!dataSource.collectionManager.getCollection(collectionName)) {
    return { collection: `Collection "${collectionName}" does not exist in data source "${dataSourceName}"` };
  }
  return null;
}
const EXECUTION_STATUS_NAMES = new Map(Object.entries(import_constants.EXECUTION_STATUS).map(([name, value]) => [value, name]));
function getExecutionStatusName(status) {
  if (typeof status === "undefined") {
    return "UNKNOWN";
  }
  return EXECUTION_STATUS_NAMES.get(status) ?? `${status}`;
}
function getWorkflowExecutionLogMeta(workflow, processor) {
  var _a, _b, _c, _d;
  const lastSavedJob = processor == null ? void 0 : processor.lastSavedJob;
  const lastNode = (_a = processor == null ? void 0 : processor.nodesMap) == null ? void 0 : _a.get(lastSavedJob == null ? void 0 : lastSavedJob.nodeId);
  return {
    workflowId: workflow.id,
    workflowKey: workflow.key,
    workflowTitle: workflow.title,
    executionId: ((_b = processor == null ? void 0 : processor.execution) == null ? void 0 : _b.id) ?? null,
    executionStatus: ((_c = processor == null ? void 0 : processor.execution) == null ? void 0 : _c.status) ?? null,
    executionStatusName: getExecutionStatusName((_d = processor == null ? void 0 : processor.execution) == null ? void 0 : _d.status),
    lastNodeId: (lastNode == null ? void 0 : lastNode.id) ?? (lastSavedJob == null ? void 0 : lastSavedJob.nodeId) ?? null,
    lastNodeType: (lastNode == null ? void 0 : lastNode.type) ?? null,
    lastJobId: (lastSavedJob == null ? void 0 : lastSavedJob.id) ?? null,
    lastJobStatus: (lastSavedJob == null ? void 0 : lastSavedJob.status) ?? null
  };
}
async function abortExecution(plugin, execution, options = {}) {
  const logger = plugin.getLogger(execution.workflowId);
  const transaction = options.transaction ?? void 0;
  const ExecutionRepo = plugin.db.getRepository("executions");
  const JobRepo = plugin.db.getRepository("jobs");
  try {
    if (!transaction) {
      return plugin.db.sequelize.transaction(
        (transaction2) => abortExecution(plugin, execution, {
          ...options,
          transaction: transaction2
        })
      );
    }
    const abortValues = {
      status: import_constants.EXECUTION_STATUS.ABORTED,
      ...options.reason ? {
        reason: options.reason
      } : {}
    };
    const expectedStatus = typeof execution.status === "undefined" ? import_constants.EXECUTION_STATUS.STARTED : execution.status;
    if (![import_constants.EXECUTION_STATUS.QUEUEING, import_constants.EXECUTION_STATUS.STARTED].includes(expectedStatus)) {
      return false;
    }
    const [affected] = await ExecutionRepo.model.update(abortValues, {
      where: {
        id: execution.id,
        status: expectedStatus
      },
      individualHooks: true,
      transaction
    });
    if (!affected) {
      return false;
    }
    const updated = await JobRepo.update({
      values: {
        status: import_constants.JOB_STATUS.ABORTED
      },
      filter: {
        executionId: execution.id,
        status: import_constants.JOB_STATUS.PENDING
      },
      individualHooks: false,
      transaction
    });
    const childExecutions = await plugin.db.getRepository("executions").find({
      filter: {
        parentExecutionId: execution.id,
        status: [import_constants.EXECUTION_STATUS.QUEUEING, import_constants.EXECUTION_STATUS.STARTED]
      },
      transaction
    });
    for (const child of childExecutions) {
      if (![import_constants.EXECUTION_STATUS.QUEUEING, import_constants.EXECUTION_STATUS.STARTED].includes(child.status)) {
        continue;
      }
      await abortExecution(plugin, child, { transaction, reason: import_constants.EXECUTION_REASON.PARENT_ABORTED });
    }
    const updateLocalState = () => {
      execution.set("status", import_constants.EXECUTION_STATUS.ABORTED);
      execution.set("reason", options.reason ?? null);
      plugin.timeoutManager.clear(execution.id);
      plugin.abortRunningExecution(execution.id, options.reason);
    };
    afterTransactionCommit(transaction, updateLocalState);
    logger.info(`execution (${execution.id}) aborted`, {
      workflowId: execution.workflowId,
      pendingJobs: Array.isArray(updated) ? updated.length : updated
    });
    return true;
  } catch (error) {
    throw error;
  }
}
function getHiddenFieldNames(model) {
  const { collection } = model.constructor;
  if (!(collection == null ? void 0 : collection.fields)) {
    return [];
  }
  return Array.from(collection.fields.values()).filter((field) => {
    var _a;
    return (_a = field == null ? void 0 : field.options) == null ? void 0 : _a.hidden;
  }).map((field) => field.options.name).filter((name) => typeof name === "string");
}
function toJSON(data) {
  if (Array.isArray(data)) {
    return data.map(toJSON);
  }
  if (!(data instanceof import_database.Model) || !data) {
    return data;
  }
  const result = { ...data.get() };
  for (const fieldName of getHiddenFieldNames(data)) {
    delete result[fieldName];
  }
  Object.keys(data.constructor.associations).forEach((key) => {
    if (result[key] != null && typeof result[key] === "object") {
      result[key] = toJSON(result[key]);
    }
  });
  return result;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  abortExecution,
  getExecutionLockKey,
  getExecutionStatusName,
  getJobLockKey,
  getWorkflowExecutionLogMeta,
  isLockAcquireError,
  toJSON,
  validateCollectionField
});
