/**
 * 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 compiler_exports = {};
__export(compiler_exports, {
  compilePlanStep: () => compilePlanStep,
  normalizePlanSelector: () => normalizePlanSelector,
  normalizePlanSteps: () => normalizePlanSteps
});
module.exports = __toCommonJS(compiler_exports);
var import_lodash = __toESM(require("lodash"));
var import_errors = require("../errors");
var import_service_utils = require("../service-utils");
var import_action_specs = require("./action-specs");
var import_step_link = require("./step-link");
var import_created_keys = require("./created-keys");
function isFlowSurfaceResolvedStepLink(selector) {
  return "step" in selector && selector.summary.source === "step";
}
function normalizePlanSelector(actionName, selector, deps, fieldName = "selector", options = {}) {
  const allowKey = options.allowKey !== false;
  if (!import_lodash.default.isPlainObject(selector)) {
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${fieldName} must be an object`);
  }
  if (allowKey && Object.keys(selector).length === 1 && typeof selector.key === "string" && selector.key.trim()) {
    return {
      key: selector.key.trim()
    };
  }
  if (Object.keys(selector).length === 1 && import_lodash.default.isPlainObject(selector.locator)) {
    return {
      locator: deps.normalizeGetTarget(selector.locator)
    };
  }
  if (Object.keys(selector).every((key) => ["step", "path"].includes(key)) && typeof selector.step === "string") {
    return (0, import_step_link.normalizeFlowSurfacePlanStepLink)(actionName, selector, fieldName);
  }
  (0, import_errors.throwBadRequest)(
    `flowSurfaces ${actionName} ${fieldName} must be ${allowKey ? "either { key }, { locator } or { step }" : "either { locator } or { step }"}`
  );
}
function normalizePlanSteps(actionName, values, deps) {
  if (!import_lodash.default.isPlainObject(values == null ? void 0 : values.plan) || !Array.isArray(values.plan.steps)) {
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} requires plan.steps[]`);
  }
  const seenIds = /* @__PURE__ */ new Set();
  return values.plan.steps.map((rawStep, index) => {
    if (!import_lodash.default.isPlainObject(rawStep)) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}] must be an object`);
    }
    if (Object.prototype.hasOwnProperty.call(rawStep, "target") || Object.prototype.hasOwnProperty.call(rawStep, "source")) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}] must use selectors.target / selectors.source`);
    }
    const action = String(rawStep.action || "").trim();
    if (!action || !(0, import_action_specs.getFlowSurfacePlanActionSpec)(action)) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}].action is not supported`);
    }
    const selectorsInput = import_lodash.default.isUndefined(rawStep.selectors) ? {} : rawStep.selectors;
    if (!import_lodash.default.isPlainObject(selectorsInput)) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}].selectors must be an object`);
    }
    const selectorKeys = Object.keys(selectorsInput || {});
    if (selectorKeys.some((key) => !["target", "source"].includes(key))) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}].selectors only supports target/source`);
    }
    const stepValues = import_lodash.default.isUndefined(rawStep.values) ? {} : rawStep.values;
    if (!import_lodash.default.isPlainObject(stepValues)) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}].values must be an object`);
    }
    const forbiddenKeys = ["target", "uid", "sourceUid", "targetUid"].filter(
      (key) => Object.prototype.hasOwnProperty.call(stepValues, key)
    );
    if (forbiddenKeys.length) {
      (0, import_errors.throwBadRequest)(
        `flowSurfaces ${actionName} plan.steps[${index}].values must not include ${forbiddenKeys.join(
          ", "
        )}; use selectors`
      );
    }
    deps.validatePayloadShape(actionName, stepValues, `plan.steps[${index}].values`);
    const id = typeof rawStep.id === "string" && rawStep.id.trim() ? rawStep.id.trim() : void 0;
    if (id) {
      if (seenIds.has(id)) {
        (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}].id '${id}' is duplicated`);
      }
      seenIds.add(id);
    }
    return {
      id,
      action,
      selectors: (0, import_service_utils.buildDefinedPayload)({
        target: import_lodash.default.isUndefined(selectorsInput.target) ? void 0 : normalizePlanSelector(actionName, selectorsInput.target, deps, `plan.steps[${index}].selectors.target`),
        source: import_lodash.default.isUndefined(selectorsInput.source) ? void 0 : normalizePlanSelector(actionName, selectorsInput.source, deps, `plan.steps[${index}].selectors.source`)
      }),
      values: import_lodash.default.cloneDeep(stepValues)
    };
  });
}
function buildPlanStepSelectorSummary(stepLink) {
  return {
    source: "step",
    step: stepLink.step,
    ...stepLink.path ? { path: stepLink.path } : {}
  };
}
async function resolvePlanSelectorInContext(actionName, selector, context, deps, fieldName, priorStepIds, priorCreatedKeys, options = {}) {
  const normalizedSelector = normalizePlanSelector(actionName, selector, deps, fieldName);
  if ("step" in normalizedSelector) {
    if (!priorStepIds.has(normalizedSelector.step)) {
      (0, import_errors.throwBadRequest)(
        `flowSurfaces ${actionName} ${fieldName}.step '${normalizedSelector.step}' is not a previous step id`
      );
    }
    return {
      ...normalizedSelector,
      summary: buildPlanStepSelectorSummary(normalizedSelector)
    };
  }
  if ("key" in normalizedSelector) {
    const keyInfo = context.keyMap.get(normalizedSelector.key);
    if (keyInfo) {
      return keyInfo;
    }
    if (priorCreatedKeys.has(normalizedSelector.key)) {
      return {
        key: normalizedSelector.key,
        summary: {
          source: "created",
          key: normalizedSelector.key
        }
      };
    }
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${fieldName}.key '${normalizedSelector.key}' is not defined`);
  }
  const resolved = await deps.resolveLocator(normalizedSelector.locator, options);
  if (!context.surfaceResolved) {
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${fieldName} locator requires surface`);
  }
  if (!context.uidSet.has(resolved.uid)) {
    (0, import_errors.throwBadRequest)(
      `flowSurfaces ${actionName} ${fieldName} locator must resolve inside the current surface '${context.surfaceResolved.uid}'`
    );
  }
  const node = context.publicNodeMap[resolved.uid] || (resolved.uid === context.surfaceResolved.uid ? context.publicTree : void 0);
  return {
    key: "",
    uid: resolved.uid,
    source: "system",
    kind: deps.buildPlanKeyKind(node, resolved.kind),
    node: node || resolved.node,
    resolved,
    locator: (0, import_service_utils.buildDefinedPayload)({
      uid: normalizedSelector.locator.uid,
      pageSchemaUid: normalizedSelector.locator.pageSchemaUid,
      tabSchemaUid: normalizedSelector.locator.tabSchemaUid,
      routeId: normalizedSelector.locator.routeId
    })
  };
}
function buildMutateOp(type, payload, opId) {
  if (import_lodash.default.isPlainObject(payload.target)) {
    return {
      ...opId ? { opId } : {},
      type,
      target: payload.target,
      values: import_lodash.default.omit(payload, ["target"])
    };
  }
  return {
    ...opId ? { opId } : {},
    type,
    values: payload
  };
}
function buildSelectorRuntimeValue(selector) {
  if ("summary" in selector) {
    if ("step" in selector) {
      return {
        step: selector.step,
        ...selector.path ? { path: selector.path } : {}
      };
    }
    return {
      key: selector.key
    };
  }
  return selector.uid;
}
function getResolvedSelectorUid(selector) {
  if (!selector || "summary" in selector) {
    return void 0;
  }
  return selector.uid;
}
function isReplaceComposeStep(step) {
  var _a;
  return step.action === "compose" && String(((_a = step.values) == null ? void 0 : _a.mode) || "").trim() === "replace";
}
function assertReplaceComposeTargetSupportsScopeResolution(actionName, index, step, target) {
  if (!isReplaceComposeStep(step) || !target || !("summary" in target) || target.summary.source !== "step") {
    return;
  }
  (0, import_errors.throwBadRequest)(
    `flowSurfaces ${actionName} plan.steps[${index}] compose replace does not support selectors.target.step; use a concrete locator or key for the existing replace target`
  );
}
function collectDescendantUids(node, carry = /* @__PURE__ */ new Set()) {
  if (!node || typeof node !== "object") {
    return carry;
  }
  for (const value of Object.values(node.subModels || {})) {
    for (const child of import_lodash.default.castArray(value)) {
      if (child == null ? void 0 : child.uid) {
        carry.add(child.uid);
      }
      collectDescendantUids(child, carry);
    }
  }
  return carry;
}
function collectNodeAndDescendantUids(node, carry = /* @__PURE__ */ new Set()) {
  if (!node || typeof node !== "object") {
    return carry;
  }
  if (node.uid) {
    carry.add(node.uid);
  }
  return collectDescendantUids(node, carry);
}
function findNodeInTreeByUid(node, uid) {
  if (!node || typeof node !== "object" || !uid) {
    return void 0;
  }
  if (node.uid === uid) {
    return node;
  }
  for (const value of Object.values(node.subModels || {})) {
    for (const child of import_lodash.default.castArray(value)) {
      const matched = findNodeInTreeByUid(child, uid);
      if (matched) {
        return matched;
      }
    }
  }
  return void 0;
}
function getContextNodeByUid(context, uid) {
  if (!uid) {
    return void 0;
  }
  return findNodeInTreeByUid(context.publicTree, uid) || findNodeInTreeByUid(context.rawTree, uid);
}
function getSingleSubModel(node, key) {
  var _a;
  const value = (_a = node == null ? void 0 : node.subModels) == null ? void 0 : _a[key];
  return Array.isArray(value) ? value[0] : value;
}
function getSubModelList(node, key) {
  var _a;
  return import_lodash.default.castArray(((_a = node == null ? void 0 : node.subModels) == null ? void 0 : _a[key]) || []).filter((item) => item && typeof item === "object");
}
function isGridNode(node) {
  return typeof (node == null ? void 0 : node.use) === "string" && node.use.endsWith("GridModel");
}
function resolveReplaceComposeGridNode(targetNode) {
  if (!targetNode || typeof targetNode !== "object") {
    return void 0;
  }
  if (isGridNode(targetNode)) {
    return targetNode;
  }
  const directGrid = getSingleSubModel(targetNode, "grid");
  if (directGrid) {
    return directGrid;
  }
  const firstTab = getSubModelList(targetNode, "tabs")[0];
  const firstTabGrid = getSingleSubModel(firstTab, "grid");
  if (firstTabGrid) {
    return firstTabGrid;
  }
  const popupPage = getSingleSubModel(targetNode, "page");
  const firstPopupTab = getSubModelList(popupPage, "tabs")[0];
  return getSingleSubModel(firstPopupTab, "grid");
}
async function collectReplaceScopeExistingKeys(step, context, target, deps, options = {}) {
  if (!isReplaceComposeStep(step)) {
    return /* @__PURE__ */ new Set();
  }
  let targetNode = getContextNodeByUid(context, getResolvedSelectorUid(target)) || (!target || "summary" in target ? void 0 : target.node);
  if (!targetNode && target && !("summary" in target) && target.resolved && deps.loadResolvedSurfaceTree) {
    targetNode = await deps.loadResolvedSurfaceTree(target.resolved, options.transaction);
  }
  if (!targetNode) {
    return /* @__PURE__ */ new Set();
  }
  const gridNode = resolveReplaceComposeGridNode(targetNode);
  if (!gridNode) {
    return /* @__PURE__ */ new Set();
  }
  const replacedUids = /* @__PURE__ */ new Set();
  for (const item of getSubModelList(gridNode, "items")) {
    collectNodeAndDescendantUids(item, replacedUids);
  }
  const keys = /* @__PURE__ */ new Set();
  context.keyMap.forEach((info, key) => {
    if (replacedUids.has(info.uid)) {
      keys.add(key);
    }
  });
  return keys;
}
function buildExistingKeysForConflict(context, priorCreatedKeys, allowedExistingKeys) {
  const existing = /* @__PURE__ */ new Set();
  context.keyMap.forEach((_info, key) => {
    if (!allowedExistingKeys.has(key)) {
      existing.add(key);
    }
  });
  priorCreatedKeys.forEach((key) => existing.add(key));
  return existing;
}
async function compilePlanStep(actionName, step, index, context, deps, priorStepIds, priorCreatedKeys, options = {}) {
  var _a, _b, _c, _d, _e, _f, _g;
  const runtimeValues = step.action === "compose" ? (0, import_created_keys.normalizeComposeInlineKeysForPlan)(step.values || {}, `plan.steps[${index}].values`) : import_lodash.default.cloneDeep(step.values || {});
  const targetSelectorKey = (0, import_created_keys.isFlowSurfacePureKeyObject)((_a = step.selectors) == null ? void 0 : _a.target) ? String(step.selectors.target.key || "").trim() : void 0;
  const createdKeys = (0, import_created_keys.collectFlowSurfaceCreatedKeys)(step.action, step.values || {}, {
    targetSelectorKey
  });
  const spec = (0, import_action_specs.getFlowSurfacePlanActionSpec)(step.action);
  if (!spec) {
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}].action '${step.action}' is not supported`);
  }
  const selectorRequirements = (0, import_action_specs.getFlowSurfacePlanSelectorRequirements)(spec.selectorMode);
  if (selectorRequirements.requiresTarget && !((_b = step.selectors) == null ? void 0 : _b.target)) {
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}] requires selectors.target`);
  }
  if (!selectorRequirements.requiresTarget && ((_c = step.selectors) == null ? void 0 : _c.target)) {
    (0, import_errors.throwBadRequest)(
      `flowSurfaces ${actionName} plan.steps[${index}] action '${step.action}' does not support selectors.target`
    );
  }
  if (selectorRequirements.requiresSource && !((_d = step.selectors) == null ? void 0 : _d.source)) {
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}] requires selectors.source`);
  }
  if (!selectorRequirements.requiresSource && ((_e = step.selectors) == null ? void 0 : _e.source)) {
    (0, import_errors.throwBadRequest)(
      `flowSurfaces ${actionName} plan.steps[${index}] action '${step.action}' does not support selectors.source`
    );
  }
  let resolvedTarget;
  let resolvedSource;
  if (selectorRequirements.requiresTarget) {
    const targetSelector = (_f = step.selectors) == null ? void 0 : _f.target;
    if (!targetSelector) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}] requires selectors.target`);
    }
    resolvedTarget = await resolvePlanSelectorInContext(
      actionName,
      targetSelector,
      context,
      deps,
      `plan.steps[${index}].selectors.target`,
      priorStepIds,
      priorCreatedKeys,
      options
    );
  }
  if (selectorRequirements.requiresSource) {
    const sourceSelector = (_g = step.selectors) == null ? void 0 : _g.source;
    if (!sourceSelector) {
      (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}] requires selectors.source`);
    }
    resolvedSource = await resolvePlanSelectorInContext(
      actionName,
      sourceSelector,
      context,
      deps,
      `plan.steps[${index}].selectors.source`,
      priorStepIds,
      priorCreatedKeys,
      options
    );
  }
  assertReplaceComposeTargetSupportsScopeResolution(actionName, index, step, resolvedTarget);
  const allowedExistingKeys = await collectReplaceScopeExistingKeys(step, context, resolvedTarget, deps, options);
  (0, import_created_keys.assertNoDuplicateFlowSurfaceCreatedKeys)(createdKeys, `flowSurfaces ${actionName} plan.steps[${index}]`, {
    existingKeys: buildExistingKeysForConflict(context, priorCreatedKeys, allowedExistingKeys),
    reservedNames: [...priorStepIds, ...step.id ? [step.id] : []]
  });
  const payload = (0, import_step_link.replaceFlowSurfacePlanStepLinks)(
    actionName,
    runtimeValues,
    `plan.steps[${index}].values`,
    priorStepIds,
    /* @__PURE__ */ new Set([...context.keyMap.keys(), ...priorCreatedKeys]),
    allowedExistingKeys
  );
  const compiled = {
    index,
    ...step.id ? { id: step.id } : {},
    action: step.action,
    payload,
    resolvedSelectors: {},
    usedKeys: [],
    usedStepLinks: [],
    createdKeys
  };
  const addUsedKey = (selector) => {
    if ("summary" in selector) {
      if (isFlowSurfaceResolvedStepLink(selector)) {
        compiled.usedStepLinks.push(selector);
      }
      return selector.summary;
    }
    if (selector.source === "request" || selector.source === "declared") {
      compiled.usedKeys.push(selector);
    }
    return {
      uid: selector.uid,
      kind: selector.kind,
      ...selector.key ? { key: selector.key } : {},
      source: selector.source
    };
  };
  if (spec.selectorMode === "none") {
    compiled.payload = payload;
  } else if (spec.selectorMode === "target") {
    const target = resolvedTarget;
    compiled.payload = {
      ...payload,
      target: {
        uid: buildSelectorRuntimeValue(target)
      }
    };
    compiled.resolvedSelectors.target = addUsedKey(target);
  } else if (spec.selectorMode === "rootUidTarget") {
    const target = resolvedTarget;
    compiled.payload = {
      ...payload,
      uid: buildSelectorRuntimeValue(target)
    };
    compiled.resolvedSelectors.target = addUsedKey(target);
  } else if (spec.selectorMode === "sourceTarget") {
    const source = resolvedSource;
    const target = resolvedTarget;
    compiled.payload = {
      ...payload,
      sourceUid: buildSelectorRuntimeValue(source),
      targetUid: buildSelectorRuntimeValue(target)
    };
    compiled.resolvedSelectors.source = addUsedKey(source);
    compiled.resolvedSelectors.target = addUsedKey(target);
  } else {
    (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} plan.steps[${index}].action '${step.action}' is not supported`);
  }
  if (spec.executionKind === "mutate") {
    compiled.mutateOp = buildMutateOp(step.action, compiled.payload, step.id);
  }
  return compiled;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  compilePlanStep,
  normalizePlanSelector,
  normalizePlanSteps
});
