/**
 * 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, {
  compileApplySpec: () => compileApplySpec
});
module.exports = __toCommonJS(compiler_exports);
var import_lodash = __toESM(require("lodash"));
var import_catalog = require("../catalog");
var import_placement = require("../placement");
var import_errors = require("../errors");
var import_node_use_sets = require("../node-use-sets");
var import_field_type_resolver = require("../field-type-resolver");
var import_event_flow_normalizer = require("../event-flow-normalizer");
var import_layout = require("./layout");
var import_matching = require("./matching");
function makeOpRef(path) {
  const normalized = String(path || "").trim();
  const [step, ...rest] = normalized.split(".");
  return {
    step,
    ...rest.length ? { path: rest.join(".") } : {}
  };
}
const FORM_GRID_USES = /* @__PURE__ */ new Set(["FormGridModel", "AssignFormGridModel"]);
const ACTION_USES = new Set(Array.from(import_catalog.ACTION_KEY_BY_USE.keys()));
const BLOCK_USES = new Set(Array.from(import_catalog.BLOCK_KEY_BY_USE.keys()));
const STANDALONE_FIELD_USES = import_node_use_sets.CREATABLE_STANDALONE_FIELD_USES;
const FORM_BLOCK_USES = import_placement.FLOW_SURFACE_FORM_BLOCK_USES;
const DETAILS_BLOCK_USES = import_placement.FLOW_SURFACE_DETAILS_BLOCK_USES;
const FILTER_FORM_BLOCK_USES = import_placement.FLOW_SURFACE_FILTER_FORM_BLOCK_USES;
const RECORD_ACTION_INTERNAL_CONTAINER_USES = /* @__PURE__ */ new Set([
  "TableActionsColumnModel",
  "ListItemModel",
  "GridCardItemModel"
]);
const APPLY_POPUP_ALLOWED_KEYS = /* @__PURE__ */ new Set(["template", "tryTemplate", "defaultType"]);
function compileApplySpec(target, currentTree, spec) {
  if (!(currentTree == null ? void 0 : currentTree.uid) || !(currentTree == null ? void 0 : currentTree.use)) {
    throw new import_errors.FlowSurfaceBadRequestError("flowSurfaces apply requires an existing target subtree");
  }
  const ops = [];
  const state = {
    seq: 0,
    clientKeyToUid: {}
  };
  if (currentTree.use === "RootPageModel") {
    syncRoutePageNode(ops, state, target, currentTree, spec);
    return {
      ops,
      clientKeyToUid: state.clientKeyToUid
    };
  }
  if (currentTree.use === "ChildPageModel") {
    syncExistingNode(
      ops,
      state,
      {
        uidRef: currentTree.uid,
        use: currentTree.use
      },
      currentTree,
      {
        uid: currentTree.uid,
        use: currentTree.use,
        props: spec.props,
        decoratorProps: spec.decoratorProps,
        stepParams: spec.stepParams,
        flowRegistry: spec.flowRegistry,
        subModels: spec.subModels
      },
      { uid: currentTree.uid }
    );
    return {
      ops,
      clientKeyToUid: state.clientKeyToUid
    };
  }
  if (currentTree.use === "RootPageTabModel") {
    syncRouteTabNode(ops, state, target, currentTree, spec);
    return {
      ops,
      clientKeyToUid: state.clientKeyToUid
    };
  }
  if (currentTree.use === "ChildPageTabModel") {
    syncTabNode(ops, state, { uid: currentTree.uid }, currentTree, spec);
    return {
      ops,
      clientKeyToUid: state.clientKeyToUid
    };
  }
  const rootSpec = {
    uid: currentTree.uid,
    use: currentTree.use,
    popup: spec.popup,
    props: spec.props,
    decoratorProps: spec.decoratorProps,
    stepParams: spec.stepParams,
    flowRegistry: spec.flowRegistry,
    subModels: spec.subModels
  };
  syncExistingNode(
    ops,
    state,
    {
      uidRef: currentTree.uid,
      use: currentTree.use
    },
    currentTree,
    rootSpec,
    target
  );
  return {
    ops,
    clientKeyToUid: state.clientKeyToUid
  };
}
function syncExistingNode(ops, state, nodeRef, currentNode, desiredNode, explicitTarget) {
  const popupAwareDesiredNode = withApplyPopupOpenViewForExistingNode(
    desiredNode,
    `flowSurfaces apply node '${desiredNode.use}'`
  );
  emitDomainSettingOps(ops, nodeRef, currentNode, popupAwareDesiredNode, explicitTarget);
  const childSync = syncChildren(ops, state, nodeRef, currentNode, popupAwareDesiredNode);
  (0, import_layout.emitLayoutOp)(ops, explicitTarget || { uid: nodeRef.uidRef }, currentNode, popupAwareDesiredNode, childSync);
}
function syncCreatedNode(ops, state, nodeRef, desiredNode) {
  emitDomainSettingOps(ops, nodeRef, null, desiredNode);
  const childSync = syncChildren(ops, state, nodeRef, null, desiredNode);
  (0, import_layout.emitLayoutOp)(ops, { uid: nodeRef.uidRef }, null, desiredNode, childSync);
}
function syncRoutePageNode(ops, state, target, currentNode, desiredNode) {
  const pageTarget = { uid: String(target.uid || currentNode.uid || "").trim() };
  syncPageNode(ops, state, pageTarget, currentNode, desiredNode);
}
function syncPageNode(ops, state, pageTarget, currentNode, desiredNode) {
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
  emitDomainSettingOps(
    ops,
    {
      uidRef: currentNode.uid,
      use: currentNode.use
    },
    currentNode,
    {
      uid: currentNode.uid,
      use: currentNode.use,
      props: desiredNode.props,
      decoratorProps: desiredNode.decoratorProps,
      stepParams: desiredNode.stepParams,
      flowRegistry: desiredNode.flowRegistry
    },
    pageTarget
  );
  if (!(0, import_matching.hasExplicitSubModelKey)(desiredNode, "tabs")) {
    return;
  }
  const hasTabsSpec = Object.prototype.hasOwnProperty.call(desiredNode.subModels || {}, "tabs");
  if (!hasTabsSpec) {
    return;
  }
  const desiredTabs = (0, import_matching.normalizeChildren)((_a = desiredNode.subModels) == null ? void 0 : _a.tabs);
  const currentTabs = (0, import_matching.normalizeChildren)((_b = currentNode.subModels) == null ? void 0 : _b.tabs);
  const tabMatchPlan = (0, import_matching.planArrayChildMatches)(currentTabs, desiredTabs, currentNode.use, "tabs");
  const desiredRefs = [];
  for (const [desiredIndex, desiredTab] of desiredTabs.entries()) {
    const currentMatch = tabMatchPlan.matchesByDesiredIndex.get(desiredIndex);
    if (currentMatch) {
      bindClientKey(state, desiredTab.clientKey, currentMatch.uid);
      desiredRefs.push({
        uidRef: currentMatch.uid,
        use: currentMatch.use
      });
      syncRouteTabNode(ops, state, { uid: currentMatch.uid }, currentMatch, desiredTab);
      continue;
    }
    const opId = nextOpId(state, "addTab");
    ops.push({
      opId,
      type: "addTab",
      values: {
        target: pageTarget,
        ...desiredTab.clientKey ? { clientKey: desiredTab.clientKey } : {},
        title: ((_e = (_d = (_c = desiredTab == null ? void 0 : desiredTab.stepParams) == null ? void 0 : _c.pageTabSettings) == null ? void 0 : _d.tab) == null ? void 0 : _e.title) || ((_f = desiredTab == null ? void 0 : desiredTab.props) == null ? void 0 : _f.title) || ((_h = (_g = desiredTab == null ? void 0 : desiredTab.props) == null ? void 0 : _g.route) == null ? void 0 : _h.title) || "Untitled",
        icon: ((_k = (_j = (_i = desiredTab == null ? void 0 : desiredTab.stepParams) == null ? void 0 : _i.pageTabSettings) == null ? void 0 : _j.tab) == null ? void 0 : _k.icon) || ((_l = desiredTab == null ? void 0 : desiredTab.props) == null ? void 0 : _l.icon),
        documentTitle: (_o = (_n = (_m = desiredTab == null ? void 0 : desiredTab.stepParams) == null ? void 0 : _m.pageTabSettings) == null ? void 0 : _n.tab) == null ? void 0 : _o.documentTitle
      }
    });
    const createdRef = {
      uidRef: makeOpRef(`${opId}.tabSchemaUid`),
      use: "RootPageTabModel",
      sourceOpId: opId
    };
    desiredRefs.push(createdRef);
    syncCreatedNode(ops, state, createdRef, desiredTab);
  }
  for (const currentTab of currentTabs) {
    if (!tabMatchPlan.matchedCurrentUids.has(currentTab.uid)) {
      ops.push({
        type: "removeTab",
        values: {
          uid: currentTab.uid
        }
      });
    }
  }
  (0, import_layout.emitMoveTabOps)(ops, desiredRefs);
}
function syncRouteTabNode(ops, state, target, currentNode, desiredNode) {
  const tabTarget = { uid: String(target.uid || currentNode.uid || "").trim() };
  syncTabNode(ops, state, tabTarget, currentNode, desiredNode);
}
function syncTabNode(ops, state, tabTarget, currentNode, desiredNode) {
  var _a, _b;
  emitDomainSettingOps(
    ops,
    {
      uidRef: currentNode.uid,
      use: currentNode.use
    },
    currentNode,
    {
      uid: currentNode.uid,
      use: currentNode.use,
      props: desiredNode.props,
      decoratorProps: desiredNode.decoratorProps,
      stepParams: desiredNode.stepParams,
      flowRegistry: desiredNode.flowRegistry
    },
    tabTarget
  );
  if (!(0, import_matching.hasExplicitSubModelKey)(desiredNode, "grid")) {
    return;
  }
  const hasGridSpec = Object.prototype.hasOwnProperty.call(desiredNode.subModels || {}, "grid");
  if (!hasGridSpec) {
    return;
  }
  const desiredGrid = (0, import_matching.normalizeChildren)((_a = desiredNode.subModels) == null ? void 0 : _a.grid)[0];
  const currentGrid = (0, import_matching.normalizeChildren)((_b = currentNode.subModels) == null ? void 0 : _b.grid)[0];
  if (!desiredGrid || !currentGrid) {
    return;
  }
  syncExistingNode(
    ops,
    state,
    {
      uidRef: currentGrid.uid,
      use: currentGrid.use
    },
    currentGrid,
    desiredGrid,
    { uid: currentGrid.uid }
  );
}
function syncChildren(ops, state, parentRef, currentParent, desiredParent) {
  const result = {
    childClientKeyRefs: {},
    finalItemRefs: [],
    itemsChanged: false,
    itemsSpecified: false
  };
  const desiredSubModels = desiredParent.subModels;
  if (!desiredSubModels) {
    return result;
  }
  const currentSubModels = (currentParent == null ? void 0 : currentParent.subModels) || {};
  const subKeys = Object.keys(desiredSubModels);
  for (const subKey of subKeys) {
    const desiredRaw = desiredSubModels[subKey];
    const currentRaw = currentSubModels[subKey];
    const desiredChildren = (0, import_matching.normalizeChildren)(desiredRaw);
    const currentChildren = (0, import_matching.normalizeChildren)(currentRaw);
    const isArraySubModel = Array.isArray(desiredRaw) || Array.isArray(currentRaw);
    if (parentRef.use === "ChildPageModel" && subKey === "tabs") {
      const tabSync = syncPopupTabs(ops, state, parentRef, currentChildren, desiredChildren);
      if (tabSync.itemsSpecified) {
        result.finalItemRefs = tabSync.finalItemRefs;
        result.itemsChanged = tabSync.itemsChanged;
        result.itemsSpecified = true;
      }
      Object.assign(result.childClientKeyRefs, tabSync.childClientKeyRefs);
      continue;
    }
    if (!isArraySubModel) {
      const desiredChild = desiredChildren[0];
      const currentChild = currentChildren[0];
      if (!desiredChild && currentChild) {
        ops.push({
          type: "removeNode",
          target: { uid: currentChild.uid }
        });
        continue;
      }
      if (!desiredChild) {
        continue;
      }
      if (currentChild && (0, import_matching.matchesObjectChild)(currentChild, desiredChild)) {
        bindClientKey(state, desiredChild.clientKey, currentChild.uid);
        if (desiredChild.clientKey) {
          result.childClientKeyRefs[desiredChild.clientKey] = currentChild.uid;
        }
        syncExistingNode(
          ops,
          state,
          {
            uidRef: currentChild.uid,
            use: currentChild.use
          },
          currentChild,
          desiredChild
        );
        continue;
      }
      if (currentChild) {
        ops.push({
          type: "removeNode",
          target: { uid: currentChild.uid }
        });
      }
      const defaultRef = getDefaultChildRef(parentRef, subKey, desiredChild.use);
      if (defaultRef) {
        if (desiredChild.clientKey) {
          result.childClientKeyRefs[desiredChild.clientKey] = defaultRef.uidRef;
        }
        syncCreatedNode(ops, state, defaultRef, desiredChild);
      } else {
        const createdRef = createDesiredChild(ops, state, parentRef, subKey, desiredChild, currentParent);
        if (desiredChild.clientKey) {
          result.childClientKeyRefs[desiredChild.clientKey] = createdRef.uidRef;
        }
      }
      continue;
    }
    const childMatchPlan = (0, import_matching.planArrayChildMatches)(currentChildren, desiredChildren, parentRef.use, subKey);
    const desiredRefs = [];
    for (const [desiredIndex, desiredChild] of desiredChildren.entries()) {
      const currentMatch = childMatchPlan.matchesByDesiredIndex.get(desiredIndex);
      if (currentMatch) {
        const currentRef = {
          uidRef: currentMatch.uid,
          use: currentMatch.use
        };
        bindClientKey(state, desiredChild.clientKey, currentMatch.uid);
        if (desiredChild.clientKey) {
          result.childClientKeyRefs[desiredChild.clientKey] = currentRef.uidRef;
        }
        desiredRefs.push(currentRef);
        syncExistingNode(ops, state, currentRef, currentMatch, desiredChild);
        continue;
      }
      const defaultRef = getDefaultChildRef(parentRef, subKey, desiredChild.use);
      if (defaultRef) {
        if (desiredChild.clientKey) {
          result.childClientKeyRefs[desiredChild.clientKey] = defaultRef.uidRef;
        }
        desiredRefs.push(defaultRef);
        syncCreatedNode(ops, state, defaultRef, desiredChild);
        continue;
      }
      const createdRef = createDesiredChild(ops, state, parentRef, subKey, desiredChild, currentParent);
      if (desiredChild.clientKey) {
        result.childClientKeyRefs[desiredChild.clientKey] = createdRef.uidRef;
      }
      desiredRefs.push(createdRef);
    }
    for (const currentChild of currentChildren) {
      if (!childMatchPlan.matchedCurrentUids.has(currentChild.uid)) {
        ops.push({
          type: "removeNode",
          target: { uid: currentChild.uid }
        });
      }
    }
    (0, import_layout.emitMoveOps)(ops, desiredRefs);
    if (subKey === "items") {
      result.finalItemRefs = desiredRefs;
      result.itemsChanged = (0, import_layout.didItemRefsChange)(currentChildren, desiredRefs);
      result.itemsSpecified = true;
    }
  }
  return result;
}
function createDesiredChild(ops, state, parentRef, subKey, desiredChild, currentParent) {
  if (desiredChild.use === "ChildPageModel" && (0, import_placement.isPopupHostUse)(parentRef.use)) {
    compilePopupPageSpec(ops, state, parentRef, desiredChild);
    return {
      uidRef: parentRef.uidRef,
      use: desiredChild.use,
      sourceOpId: parentRef.sourceOpId
    };
  }
  if ((isFieldWrapperNode(desiredChild.use) || STANDALONE_FIELD_USES.has(desiredChild.use)) && isFieldContainer(parentRef.use, subKey)) {
    return createFieldNode(ops, state, parentRef, desiredChild);
  }
  if (subKey === "actions" && isActionContainer(parentRef.use)) {
    if (!ACTION_USES.has(desiredChild.use)) {
      throw new import_errors.FlowSurfaceBadRequestError(
        `flowSurfaces apply action '${desiredChild.use}' is not a public capability`
      );
    }
    return createActionNode(ops, state, parentRef, desiredChild, currentParent);
  }
  if (isBlockContainer(parentRef.use, subKey)) {
    if (!BLOCK_USES.has(desiredChild.use)) {
      throw new import_errors.FlowSurfaceBadRequestError(`flowSurfaces apply block '${desiredChild.use}' is not a public capability`);
    }
    return createBlockNode(ops, state, parentRef, desiredChild);
  }
  if (isFieldContainer(parentRef.use, subKey) && !import_node_use_sets.FIELD_WRAPPER_USES.has(desiredChild.use) && !STANDALONE_FIELD_USES.has(desiredChild.use)) {
    throw new import_errors.FlowSurfaceBadRequestError(
      `flowSurfaces apply field wrapper '${desiredChild.use}' is not a public capability`
    );
  }
  throw new import_errors.FlowSurfaceBadRequestError(
    `flowSurfaces apply cannot create '${desiredChild.use}' under '${parentRef.use}.${subKey}'`
  );
}
function createBlockNode(ops, state, parentRef, desiredNode) {
  const blockCatalogItem = (0, import_catalog.resolveSupportedBlockCatalogItem)(
    {
      use: desiredNode.use
    },
    {
      requireCreateSupported: true
    }
  );
  const opId = nextOpId(state, "addBlock");
  ops.push({
    opId,
    type: "addBlock",
    values: {
      target: {
        uid: parentRef.uidRef
      },
      ...desiredNode.clientKey ? { clientKey: desiredNode.clientKey } : {},
      type: blockCatalogItem.key,
      resourceInit: extractResourceInit(desiredNode)
    }
  });
  const ref = {
    uidRef: makeOpRef(`${opId}.uid`),
    use: desiredNode.use,
    sourceOpId: opId
  };
  syncCreatedNode(ops, state, ref, desiredNode);
  return ref;
}
function normalizeApplyPopup(desiredNode, context) {
  var _a;
  if (import_lodash.default.isUndefined(desiredNode.popup)) {
    return void 0;
  }
  if (!import_lodash.default.isPlainObject(desiredNode.popup)) {
    throw new import_errors.FlowSurfaceBadRequestError(`${context} popup must be an object`);
  }
  const invalidKeys = Object.keys(desiredNode.popup).filter((key) => !APPLY_POPUP_ALLOWED_KEYS.has(key));
  if (invalidKeys.length) {
    throw new import_errors.FlowSurfaceBadRequestError(
      `${context} popup only supports ${Array.from(APPLY_POPUP_ALLOWED_KEYS).join(", ")} in flowSurfaces apply`
    );
  }
  const hasPopupPageSpec = !!(0, import_matching.normalizeChildren)((_a = desiredNode.subModels) == null ? void 0 : _a.page)[0];
  if (hasPopupPageSpec) {
    throw new import_errors.FlowSurfaceBadRequestError(
      `${context} cannot mix popup template semantics with explicit popup subtree content in flowSurfaces apply`
    );
  }
  const nextPopup = import_lodash.default.cloneDeep(desiredNode.popup);
  if (!import_lodash.default.isUndefined(nextPopup.tryTemplate) && typeof nextPopup.tryTemplate !== "boolean") {
    throw new import_errors.FlowSurfaceBadRequestError(`${context} popup.tryTemplate must be a boolean`);
  }
  if (!import_lodash.default.isUndefined(nextPopup.defaultType) && nextPopup.defaultType !== "view" && nextPopup.defaultType !== "edit") {
    throw new import_errors.FlowSurfaceBadRequestError(`${context} popup.defaultType must be 'view' or 'edit'`);
  }
  if (import_lodash.default.isUndefined(nextPopup.template) && nextPopup.tryTemplate !== true && import_lodash.default.isUndefined(nextPopup.defaultType)) {
    return void 0;
  }
  if (!(0, import_placement.isPopupHostUse)(desiredNode.use)) {
    throw new import_errors.FlowSurfaceBadRequestError(
      `${context} popup is only supported on popup-capable action or field nodes in flowSurfaces apply`
    );
  }
  return nextPopup;
}
function buildApplyPopupStepParams(use, popup) {
  if (!popup) {
    return void 0;
  }
  if (use === "UploadActionModel") {
    return {
      selectExitRecordSettings: {
        openView: popup
      }
    };
  }
  return {
    popupSettings: {
      openView: popup
    }
  };
}
function withApplyPopupOpenViewForExistingNode(desiredNode, context) {
  const popup = normalizeApplyPopup(desiredNode, context);
  if (!popup) {
    return desiredNode;
  }
  return {
    ...desiredNode,
    stepParams: import_lodash.default.merge({}, desiredNode.stepParams || {}, buildApplyPopupStepParams(desiredNode.use, popup))
  };
}
function createActionNode(ops, state, parentRef, desiredNode, currentParent) {
  const popup = normalizeApplyPopup(desiredNode, `flowSurfaces apply action '${desiredNode.use}'`);
  const actionCatalogItem = (0, import_catalog.resolveSupportedActionCatalogItem)(
    {
      use: desiredNode.use,
      containerUse: parentRef.use
    },
    {
      requireCreateSupported: true
    }
  );
  const opType = actionCatalogItem.scope === "record" ? "addRecordAction" : "addAction";
  const targetUidRef = actionCatalogItem.scope === "record" ? resolveRecordActionCreateTargetUidRef(parentRef, currentParent) : parentRef.uidRef;
  const opId = nextOpId(state, opType);
  ops.push({
    opId,
    type: opType,
    values: {
      target: {
        uid: targetUidRef
      },
      ...desiredNode.clientKey ? { clientKey: desiredNode.clientKey } : {},
      type: actionCatalogItem.key,
      resourceInit: extractResourceInit(desiredNode),
      ...popup ? { popup } : {}
    }
  });
  const ref = {
    uidRef: makeOpRef(`${opId}.uid`),
    use: desiredNode.use,
    sourceOpId: opId
  };
  syncCreatedNode(ops, state, ref, desiredNode);
  return ref;
}
function createFieldNode(ops, state, parentRef, desiredNode) {
  var _a, _b, _c;
  const popup = normalizeApplyPopup(desiredNode, `flowSurfaces apply field '${desiredNode.use}'`);
  const standaloneType = desiredNode.use === "JSColumnModel" ? "jsColumn" : desiredNode.use === "JSItemModel" ? "jsItem" : desiredNode.use === "DividerItemModel" ? "divider" : void 0;
  if (standaloneType) {
    if (popup) {
      throw new import_errors.FlowSurfaceBadRequestError(
        `flowSurfaces apply field '${desiredNode.use}' popup is not supported for standalone field types`
      );
    }
    const opId2 = nextOpId(state, "addField");
    ops.push({
      opId: opId2,
      type: "addField",
      values: {
        target: {
          uid: parentRef.uidRef
        },
        ...desiredNode.clientKey ? { clientKey: desiredNode.clientKey } : {},
        type: standaloneType
      }
    });
    const ref2 = {
      uidRef: makeOpRef(`${opId2}.uid`),
      use: desiredNode.use,
      sourceOpId: opId2
    };
    syncCreatedNode(ops, state, ref2, desiredNode);
    return ref2;
  }
  const innerField = (0, import_matching.normalizeChildren)((_a = desiredNode.subModels) == null ? void 0 : _a.field)[0];
  const requestedRenderer = (innerField == null ? void 0 : innerField.use) === "JSFieldModel" || (innerField == null ? void 0 : innerField.use) === "JSEditableFieldModel" ? "js" : void 0;
  const fieldCapability = (0, import_catalog.resolveSupportedFieldCapability)({
    containerUse: parentRef.use,
    requestedWrapperUse: desiredNode.use,
    requestedFieldUse: requestedRenderer ? void 0 : innerField == null ? void 0 : innerField.use,
    requestedRenderer,
    allowUnresolvedFieldUse: true
  });
  const fieldInit = import_lodash.default.get(innerField, ["stepParams", "fieldSettings", "init"]) || import_lodash.default.get(desiredNode, ["stepParams", "fieldSettings", "init"]);
  const defaultTargetUid = import_lodash.default.get(desiredNode, ["stepParams", "filterFormItemSettings", "init", "defaultTargetUid"]);
  const fieldType = (0, import_field_type_resolver.getPublicFieldTypeForUse)(((_c = (_b = innerField == null ? void 0 : innerField.stepParams) == null ? void 0 : _b.fieldBinding) == null ? void 0 : _c.use) || (innerField == null ? void 0 : innerField.use));
  if (!(fieldInit == null ? void 0 : fieldInit.fieldPath)) {
    throw new import_errors.FlowSurfaceBadRequestError(
      `flowSurfaces apply field '${desiredNode.use}' requires stepParams.fieldSettings.init.fieldPath`
    );
  }
  const opId = nextOpId(state, "addField");
  ops.push({
    opId,
    type: "addField",
    values: {
      target: {
        uid: parentRef.uidRef
      },
      ...desiredNode.clientKey ? { clientKey: desiredNode.clientKey } : {},
      fieldPath: fieldInit.fieldPath,
      associationPathName: fieldInit.associationPathName,
      dataSourceKey: fieldInit.dataSourceKey,
      collectionName: fieldInit.collectionName,
      ...requestedRenderer ? { renderer: requestedRenderer } : {},
      ...fieldType ? { fieldType } : {},
      ...defaultTargetUid ? { defaultTargetUid } : {},
      ...popup ? { popup } : {}
    }
  });
  const ref = {
    uidRef: makeOpRef(`${opId}.wrapperUid`),
    use: desiredNode.use,
    sourceOpId: opId,
    defaultFieldUse: fieldCapability.fieldUse
  };
  syncCreatedNode(ops, state, ref, desiredNode);
  return ref;
}
function compilePopupPageSpec(ops, state, hostRef, pageSpec) {
  var _a, _b, _c;
  const tabSpec = (0, import_matching.normalizeChildren)((_a = pageSpec.subModels) == null ? void 0 : _a.tabs)[0];
  const gridSpec = (0, import_matching.normalizeChildren)((_b = tabSpec == null ? void 0 : tabSpec.subModels) == null ? void 0 : _b.grid)[0];
  const popupItems = (0, import_matching.normalizeChildren)((_c = gridSpec == null ? void 0 : gridSpec.subModels) == null ? void 0 : _c.items);
  if (!tabSpec || !gridSpec) {
    throw new import_errors.FlowSurfaceBadRequestError(
      `flowSurfaces apply popup page creation under '${hostRef.use}' requires popup page -> tab -> grid`
    );
  }
  const { childRefs, childClientKeyRefs, popupGridUidRef, popupPageRef, popupTabRef, placeholderRef } = bootstrapPopupShellCreation(ops, state, hostRef, pageSpec, tabSpec, popupItems);
  if (popupPageRef) {
    emitDomainSettingOps(ops, popupPageRef, null, pageSpec);
  }
  if (popupTabRef) {
    emitDomainSettingOps(ops, popupTabRef, null, tabSpec);
  }
  if (popupGridUidRef) {
    emitDomainSettingOps(
      ops,
      {
        uidRef: popupGridUidRef,
        use: gridSpec.use
      },
      null,
      gridSpec
    );
    if (placeholderRef) {
      ops.push({
        type: "removeNode",
        values: {
          target: {
            uid: placeholderRef.uidRef
          }
        }
      });
    }
    (0, import_layout.emitLayoutOp)(ops, { uid: popupGridUidRef }, null, gridSpec, {
      childClientKeyRefs,
      finalItemRefs: childRefs,
      itemsChanged: true,
      itemsSpecified: true
    });
    (0, import_layout.emitMoveOps)(ops, childRefs);
  }
}
function bootstrapPopupShellCreation(ops, state, hostRef, pageSpec, tabSpec, popupItems) {
  const result = {
    childRefs: [],
    childClientKeyRefs: {},
    popupGridUidRef: null,
    popupPageRef: null,
    popupTabRef: null,
    placeholderRef: null
  };
  const bindPopupShellRefs = (created) => {
    result.popupPageRef = {
      uidRef: makeOpRef(`${created.sourceOpId}.popupPageUid`),
      use: pageSpec.use
    };
    result.popupTabRef = {
      uidRef: makeOpRef(`${created.sourceOpId}.popupTabUid`),
      use: tabSpec.use,
      sourceOpId: created.sourceOpId
    };
    result.popupGridUidRef = makeOpRef(`${created.sourceOpId}.popupGridUid`);
  };
  if (!popupItems.length) {
    result.placeholderRef = createBlockNode(ops, state, hostRef, {
      use: "MarkdownBlockModel"
    });
    bindPopupShellRefs(result.placeholderRef);
    return result;
  }
  popupItems.forEach((itemSpec, index) => {
    if (index === 0) {
      const created2 = createBlockNode(ops, state, hostRef, itemSpec);
      result.childRefs.push(created2);
      if (itemSpec.clientKey) {
        result.childClientKeyRefs[itemSpec.clientKey] = created2.uidRef;
      }
      bindPopupShellRefs(created2);
      return;
    }
    const popupGridRef = {
      uidRef: result.popupGridUidRef,
      use: "BlockGridModel"
    };
    const created = createBlockNode(ops, state, popupGridRef, itemSpec);
    if (itemSpec.clientKey) {
      result.childClientKeyRefs[itemSpec.clientKey] = created.uidRef;
    }
    result.childRefs.push(created);
  });
  return result;
}
function emitDomainSettingOps(ops, nodeRef, currentNode, desiredNode, explicitTarget) {
  const props = (0, import_layout.omitLayoutProps)(desiredNode.props);
  const currentProps = (0, import_layout.omitLayoutProps)(currentNode == null ? void 0 : currentNode.props);
  const values = {};
  if (!import_lodash.default.isNil(props) && !import_lodash.default.isEqual(props, currentProps)) {
    values.props = props;
  }
  if (!import_lodash.default.isNil(desiredNode.decoratorProps) && !import_lodash.default.isEqual(desiredNode.decoratorProps, currentNode == null ? void 0 : currentNode.decoratorProps)) {
    values.decoratorProps = desiredNode.decoratorProps;
  }
  if (!import_lodash.default.isNil(desiredNode.stepParams) && !import_lodash.default.isEqual(desiredNode.stepParams, currentNode == null ? void 0 : currentNode.stepParams)) {
    values.stepParams = desiredNode.stepParams;
  }
  if (Object.keys(values).length) {
    ops.push({
      type: "updateSettings",
      target: explicitTarget || { uid: nodeRef.uidRef },
      values
    });
  }
  emitFlowRegistryOps(ops, nodeRef, currentNode, desiredNode, explicitTarget);
}
function emitFlowRegistryOps(ops, nodeRef, currentNode, desiredNode, explicitTarget) {
  if (import_lodash.default.isNil(desiredNode.flowRegistry)) {
    return;
  }
  const target = explicitTarget || { uid: nodeRef.uidRef };
  const currentFlowRegistry = import_lodash.default.isPlainObject(currentNode == null ? void 0 : currentNode.flowRegistry) ? (0, import_event_flow_normalizer.normalizeFlowSurfaceEventFlowRegistry)("apply", currentNode.flowRegistry) : {};
  const desiredFlowRegistry = import_lodash.default.isPlainObject(desiredNode.flowRegistry) ? (0, import_event_flow_normalizer.normalizeFlowSurfaceEventFlowRegistry)("apply", desiredNode.flowRegistry) : {};
  if (import_lodash.default.isEqual(desiredFlowRegistry, currentFlowRegistry)) {
    return;
  }
  const currentKeys = Object.keys(currentFlowRegistry);
  const desiredKeys = Object.keys(desiredFlowRegistry);
  for (const key of currentKeys) {
    if (!Object.prototype.hasOwnProperty.call(desiredFlowRegistry, key)) {
      ops.push({
        type: "removeEventFlow",
        target,
        values: {
          key
        }
      });
    }
  }
  for (const key of desiredKeys) {
    const flow = desiredFlowRegistry[key];
    if (Object.prototype.hasOwnProperty.call(currentFlowRegistry, key)) {
      if (import_lodash.default.isEqual(flow, currentFlowRegistry[key])) {
        continue;
      }
      ops.push({
        type: "setEventFlow",
        target,
        values: {
          key,
          flow
        }
      });
      continue;
    }
    if ((0, import_event_flow_normalizer.isFlowSurfaceBeforeAllEventFlow)(flow)) {
      ops.push({
        type: "addEventFlow",
        target,
        values: {
          key,
          flow
        }
      });
      continue;
    }
    ops.push({
      type: "setEventFlow",
      target,
      values: {
        key,
        flow
      }
    });
  }
}
function getDefaultChildRef(parentRef, subKey, childUse) {
  if (!parentRef.sourceOpId || !childUse) {
    return null;
  }
  if (FORM_BLOCK_USES.has(parentRef.use) && subKey === "grid" && FORM_GRID_USES.has(childUse)) {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.gridUid`),
      use: childUse
    };
  }
  if (DETAILS_BLOCK_USES.has(parentRef.use) && subKey === "grid" && childUse === "DetailsGridModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.gridUid`),
      use: childUse
    };
  }
  if (FILTER_FORM_BLOCK_USES.has(parentRef.use) && subKey === "grid" && childUse === "FilterFormGridModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.gridUid`),
      use: childUse
    };
  }
  if (parentRef.use === "ChildPageTabModel" && subKey === "grid" && childUse === "BlockGridModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.popupGridUid`),
      use: childUse
    };
  }
  if (parentRef.use === "TableBlockModel" && subKey === "columns" && childUse === "TableActionsColumnModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.actionsColumnUid`),
      use: childUse,
      sourceOpId: parentRef.sourceOpId,
      ownerUidRef: parentRef.uidRef
    };
  }
  if (parentRef.use === "ListBlockModel" && subKey === "item" && childUse === "ListItemModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.itemUid`),
      use: childUse,
      sourceOpId: parentRef.sourceOpId,
      ownerUidRef: parentRef.uidRef
    };
  }
  if (parentRef.use === "GridCardBlockModel" && subKey === "item" && childUse === "GridCardItemModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.itemUid`),
      use: childUse,
      sourceOpId: parentRef.sourceOpId,
      ownerUidRef: parentRef.uidRef
    };
  }
  if (parentRef.use === "ListItemModel" && subKey === "grid" && childUse === "DetailsGridModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.gridUid`),
      use: childUse
    };
  }
  if (parentRef.use === "GridCardItemModel" && subKey === "grid" && childUse === "DetailsGridModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.gridUid`),
      use: childUse
    };
  }
  if (import_node_use_sets.FIELD_WRAPPER_USES.has(parentRef.use) && subKey === "field" && childUse === (parentRef.defaultFieldUse || fieldUseFromAddFieldRenderer(parentRef))) {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.fieldUid`),
      use: childUse
    };
  }
  if (parentRef.use === "RootPageTabModel" && subKey === "grid" && childUse === "BlockGridModel") {
    return {
      uidRef: makeOpRef(`${parentRef.sourceOpId}.gridUid`),
      use: childUse
    };
  }
  return null;
}
function resolveRecordActionCreateTargetUidRef(parentRef, currentParent) {
  if (!RECORD_ACTION_INTERNAL_CONTAINER_USES.has(parentRef.use)) {
    return parentRef.uidRef;
  }
  const ownerUidRef = parentRef.ownerUidRef ?? (currentParent == null ? void 0 : currentParent.parentId);
  if (ownerUidRef) {
    return ownerUidRef;
  }
  throw new import_errors.FlowSurfaceBadRequestError(
    `flowSurfaces apply cannot resolve owning surface for record action container '${parentRef.use}'`
  );
}
function fieldUseFromAddFieldRenderer(parentRef) {
  if (!parentRef.sourceOpId || !String(parentRef.sourceOpId).startsWith("addField_")) {
    return void 0;
  }
  switch (parentRef.use) {
    case "FormItemModel":
      return "JSEditableFieldModel";
    case "DetailsItemModel":
    case "TableColumnModel":
      return "JSFieldModel";
    default:
      return void 0;
  }
}
function isFieldWrapperNode(use) {
  return (0, import_placement.isFieldWrapperUse)(use);
}
function isFieldContainer(parentUse, subKey) {
  return (0, import_placement.isFieldContainerUse)(parentUse, subKey);
}
function isBlockContainer(parentUse, subKey) {
  return (0, import_placement.isBlockContainerUse)(parentUse, subKey);
}
function isActionContainer(parentUse) {
  return (0, import_placement.isActionContainerUse)(parentUse);
}
function extractResourceInit(node) {
  return import_lodash.default.get(node, ["stepParams", "resourceSettings", "init"]);
}
function nextOpId(state, prefix) {
  state.seq += 1;
  return `${prefix}_${state.seq}`;
}
function bindClientKey(state, clientKey, uid) {
  if (!clientKey || typeof uid !== "string") {
    return;
  }
  state.clientKeyToUid[clientKey] = uid;
}
function syncPopupTabs(ops, state, popupPageRef, currentTabs, desiredTabs) {
  const result = {
    childClientKeyRefs: {},
    finalItemRefs: [],
    itemsChanged: false,
    itemsSpecified: false
  };
  const tabMatchPlan = (0, import_matching.planArrayChildMatches)(currentTabs, desiredTabs, popupPageRef.use, "tabs");
  const desiredRefs = [];
  for (const [desiredIndex, desiredTab] of desiredTabs.entries()) {
    const currentMatch = tabMatchPlan.matchesByDesiredIndex.get(desiredIndex);
    if (currentMatch) {
      const currentRef = {
        uidRef: currentMatch.uid,
        use: currentMatch.use
      };
      bindClientKey(state, desiredTab.clientKey, currentMatch.uid);
      if (desiredTab.clientKey) {
        result.childClientKeyRefs[desiredTab.clientKey] = currentRef.uidRef;
      }
      desiredRefs.push(currentRef);
      syncTabNode(ops, state, { uid: currentMatch.uid }, currentMatch, desiredTab);
      continue;
    }
    const createdRef = createPopupTabNode(ops, state, popupPageRef, desiredTab);
    if (desiredTab.clientKey) {
      result.childClientKeyRefs[desiredTab.clientKey] = createdRef.uidRef;
    }
    desiredRefs.push(createdRef);
  }
  for (const currentTab of currentTabs) {
    if (!tabMatchPlan.matchedCurrentUids.has(currentTab.uid)) {
      ops.push({
        type: "removePopupTab",
        values: {
          target: {
            uid: currentTab.uid
          }
        }
      });
    }
  }
  (0, import_layout.emitMovePopupTabOps)(ops, desiredRefs);
  return result;
}
function createPopupTabNode(ops, state, popupPageRef, desiredNode) {
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
  const opId = nextOpId(state, "addPopupTab");
  ops.push({
    opId,
    type: "addPopupTab",
    values: {
      target: {
        uid: popupPageRef.uidRef
      },
      ...desiredNode.clientKey ? { clientKey: desiredNode.clientKey } : {},
      title: ((_c = (_b = (_a = desiredNode == null ? void 0 : desiredNode.stepParams) == null ? void 0 : _a.pageTabSettings) == null ? void 0 : _b.tab) == null ? void 0 : _c.title) || ((_d = desiredNode == null ? void 0 : desiredNode.props) == null ? void 0 : _d.title) || ((_f = (_e = desiredNode == null ? void 0 : desiredNode.props) == null ? void 0 : _e.route) == null ? void 0 : _f.title) || "Untitled",
      icon: ((_i = (_h = (_g = desiredNode == null ? void 0 : desiredNode.stepParams) == null ? void 0 : _g.pageTabSettings) == null ? void 0 : _h.tab) == null ? void 0 : _i.icon) || ((_j = desiredNode == null ? void 0 : desiredNode.props) == null ? void 0 : _j.icon),
      documentTitle: (_m = (_l = (_k = desiredNode == null ? void 0 : desiredNode.stepParams) == null ? void 0 : _k.pageTabSettings) == null ? void 0 : _l.tab) == null ? void 0 : _m.documentTitle
    }
  });
  const ref = {
    uidRef: makeOpRef(`${opId}.popupTabUid`),
    use: "ChildPageTabModel",
    sourceOpId: opId
  };
  syncCreatedNode(ops, state, ref, desiredNode);
  return ref;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  compileApplySpec
});
