/**
 * 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 compose_runtime_exports = {};
__export(compose_runtime_exports, {
  createComposeRuntimeState: () => createComposeRuntimeState,
  executeComposeRuntime: () => executeComposeRuntime
});
module.exports = __toCommonJS(compose_runtime_exports);
var import_errors = require("./errors");
var import_default_action_popup = require("./default-action-popup");
var import_compose_compiler = require("./compose-compiler");
async function executeComposeRuntime(plan, deps) {
  assertComposeRuntimeDeps(plan, deps);
  const state = createComposeRuntimeState();
  await removeExistingItemsForReplace(plan, deps);
  await createBlocks(plan, deps, state);
  await applyBlockSettings(deps, state);
  await createFields(plan, deps, state);
  await applyBlockFieldLayouts(deps, state);
  await createActions(plan, deps, state);
  await createRecordActions(plan, deps, state);
  const layoutResult = await applyComposeLayout(plan, deps, state);
  return {
    target: {
      uid: plan.gridUid
    },
    mode: plan.mode,
    blocks: state.blocks.map((block) => ({
      key: block.spec.key,
      type: block.spec.type,
      uid: block.result.uid,
      gridUid: block.result.gridUid,
      itemUid: block.result.itemUid,
      itemGridUid: block.result.itemGridUid,
      actionsColumnUid: block.result.actionsColumnUid,
      fields: block.fieldResults,
      actions: block.actionResults,
      recordActions: block.recordActionResults
    })),
    ...typeof layoutResult === "undefined" ? {} : { layout: layoutResult }
  };
}
function createComposeRuntimeState() {
  return {
    keyMap: {},
    blocks: []
  };
}
function shouldApplyActionPopupAfterEffect(spec) {
  return hasPopupAfterEffect(spec.popup) || (0, import_default_action_popup.isFlowSurfaceDefaultActionPopupType)(spec.type);
}
function assertComposeRuntimeDeps(plan, deps) {
  if (plan.mode === "replace" && plan.existingItemUids.length) {
    requireComposeRuntimeDep("removeExistingItem", deps.removeExistingItem, "replace");
  }
  if (plan.blocks.some((block) => hasInlineSettings(block.spec.settings))) {
    requireComposeRuntimeDep("applyNodeSettings", deps.applyNodeSettings, "block settings");
  }
  if (plan.fields.some((field) => hasInlineSettings(field.spec.settings))) {
    requireComposeRuntimeDep("applyFieldSettings", deps.applyFieldSettings, "field settings");
  }
  if ([...plan.actions, ...plan.recordActions].some(
    (action) => hasInlineSettings(action.spec.settings) || shouldApplyActionPopupAfterEffect(action.spec)
  )) {
    if ([...plan.actions, ...plan.recordActions].some((action) => hasInlineSettings(action.spec.settings))) {
      requireComposeRuntimeDep("applyNodeSettings", deps.applyNodeSettings, "action settings");
    }
    if ([...plan.actions, ...plan.recordActions].some((action) => shouldApplyActionPopupAfterEffect(action.spec))) {
      requireComposeRuntimeDep("applyActionPopup", deps.applyActionPopup, "action popup");
    }
  }
}
function requireComposeRuntimeDep(name, dep, stage) {
  if (dep) {
    return;
  }
  (0, import_errors.throwConflict)(
    `flowSurfaces compose ${stage} runtime deps missing '${name}'`,
    "FLOW_SURFACE_COMPOSE_RUNTIME_DEPS_MISSING"
  );
}
async function removeExistingItemsForReplace(plan, deps) {
  if (plan.mode !== "replace" || !plan.existingItemUids.length) {
    return;
  }
  const removeExistingItem = deps.removeExistingItem;
  requireComposeRuntimeDep("removeExistingItem", removeExistingItem, "replace");
  for (const uid of plan.existingItemUids) {
    await removeExistingItem(uid);
  }
}
async function createBlocks(plan, deps, state) {
  for (const blockTask of plan.blocks) {
    const result = await deps.createBlock(blockTask.payload, blockTask.spec);
    state.blocks.push({
      spec: blockTask.spec,
      result,
      createdFields: [],
      fieldResults: [],
      actionResults: [],
      recordActionResults: []
    });
    state.keyMap[blockTask.key] = {
      uid: result.uid,
      gridUid: result.gridUid,
      itemUid: result.itemUid,
      itemGridUid: result.itemGridUid,
      actionsColumnUid: result.actionsColumnUid
    };
  }
}
async function applyBlockSettings(deps, state) {
  const applyNodeSettings = deps.applyNodeSettings;
  if (!applyNodeSettings) {
    return;
  }
  for (const block of state.blocks) {
    if (!hasInlineSettings(block.spec.settings)) {
      continue;
    }
    const settings = deps.resolveBlockSettings ? await deps.resolveBlockSettings(block.spec.settings || {}, state, block) : block.spec.settings;
    await applyNodeSettings("compose block", block.result.uid, settings);
  }
}
async function createFields(plan, deps, state) {
  for (const fieldTask of plan.fields) {
    const block = requireBlockState(fieldTask.blockKey, state);
    const targetUid = fieldTask.containerSource === "item" ? block.result.itemUid || block.result.uid : block.result.uid;
    const targetKey = readComposeFieldTargetKey(fieldTask.spec.target);
    const resolvedTargetUid = targetKey ? (0, import_compose_compiler.resolveComposeTargetKey)(targetKey, state.keyMap, "field") : fieldTask.spec.defaultTargetUid || fieldTask.spec.targetBlockUid;
    let createdField;
    try {
      createdField = await deps.createField(
        {
          target: {
            uid: targetUid
          },
          ...fieldTask.payload,
          ...resolvedTargetUid ? { defaultTargetUid: resolvedTargetUid } : {},
          ...fieldTask.spec.targetBlockUid ? { targetBlockUid: fieldTask.spec.targetBlockUid } : {}
        },
        fieldTask.spec,
        block.result
      );
    } catch (error) {
      const decision = deps.onFieldError ? await deps.onFieldError({
        error,
        spec: fieldTask.spec,
        blockSpec: block.spec,
        blockResult: block.result
      }) : void 0;
      if (decision === "continue") {
        continue;
      }
      throw error;
    }
    if (!createdField) {
      continue;
    }
    block.createdFields.push({
      spec: fieldTask.spec,
      result: createdField
    });
    if (deps.applyFieldSettings && hasInlineSettings(fieldTask.spec.settings)) {
      await deps.applyFieldSettings("compose field", createdField, fieldTask.spec.settings);
    }
    block.fieldResults.push(buildFieldResultSummary(fieldTask.spec, createdField));
  }
}
async function applyBlockFieldLayouts(deps, state) {
  const buildExplicitLayoutPayload = deps.buildExplicitLayoutPayload;
  const setLayout = deps.setLayout;
  for (const block of state.blocks) {
    if (!hasInlineSettings(block.spec.fieldsLayout)) {
      continue;
    }
    requireComposeRuntimeDep("buildExplicitLayoutPayload", buildExplicitLayoutPayload, "field layout");
    requireComposeRuntimeDep("setLayout", setLayout, "field layout");
    const createdByKey = Object.fromEntries(
      block.createdFields.flatMap(({ spec, result }) => {
        const uid = resolveComposeFieldLayoutUid(result);
        return uid ? [[spec.key, { uid }]] : [];
      })
    );
    const layoutPayload = await buildExplicitLayoutPayload({
      layout: block.spec.fieldsLayout,
      createdByKey,
      targetUid: block.result.uid
    });
    await setLayout({
      target: {
        uid: block.result.uid
      },
      ...layoutPayload
    });
  }
}
async function createActions(plan, deps, state) {
  for (const actionTask of plan.actions) {
    const block = requireBlockState(actionTask.blockKey, state);
    const settings = await resolveComposeActionSettings(deps, state, block, actionTask.spec, "compose action");
    const shouldPassSettingsDuringCreate = actionTask.spec.type === "aiEmployee" && hasInlineSettings(settings);
    const createdAction = await deps.createAction(
      {
        target: {
          uid: block.result.uid
        },
        ...actionTask.payload,
        ...shouldPassSettingsDuringCreate ? { settings } : {}
      },
      actionTask.spec,
      block.result
    );
    if (deps.applyNodeSettings && hasInlineSettings(settings) && !shouldPassSettingsDuringCreate) {
      await deps.applyNodeSettings("compose action", createdAction.uid, settings);
    }
    if (deps.applyActionPopup && shouldApplyActionPopupAfterEffect(actionTask.spec)) {
      await deps.applyActionPopup("compose action", createdAction.uid, actionTask.spec.popup);
    }
    const actionKeys = deps.collectActionKeys ? await deps.collectActionKeys(createdAction.uid) : {};
    block.actionResults.push(buildActionResultSummary(actionTask.spec, createdAction, actionKeys));
  }
}
async function createRecordActions(plan, deps, state) {
  for (const recordActionTask of plan.recordActions) {
    const block = requireBlockState(recordActionTask.blockKey, state);
    const settings = await resolveComposeActionSettings(
      deps,
      state,
      block,
      recordActionTask.spec,
      "compose recordAction"
    );
    const shouldPassSettingsDuringCreate = recordActionTask.spec.type === "aiEmployee" && hasInlineSettings(settings);
    const createdAction = await deps.createRecordAction(
      {
        target: {
          uid: block.result.uid
        },
        ...recordActionTask.payload,
        ...shouldPassSettingsDuringCreate ? { settings } : {}
      },
      recordActionTask.spec,
      block.result
    );
    if (!block.result.actionsColumnUid && block.spec.type === "table" && createdAction.parentUid) {
      block.result.actionsColumnUid = createdAction.parentUid;
      state.keyMap[recordActionTask.blockKey] = {
        ...state.keyMap[recordActionTask.blockKey],
        actionsColumnUid: createdAction.parentUid
      };
    }
    if (deps.applyNodeSettings && hasInlineSettings(settings) && !shouldPassSettingsDuringCreate) {
      await deps.applyNodeSettings("compose recordAction", createdAction.uid, settings);
    }
    if (deps.applyActionPopup && shouldApplyActionPopupAfterEffect(recordActionTask.spec)) {
      await deps.applyActionPopup("compose recordAction", createdAction.uid, recordActionTask.spec.popup);
    }
    const actionKeys = deps.collectActionKeys ? await deps.collectActionKeys(createdAction.uid) : {};
    block.recordActionResults.push(buildActionResultSummary(recordActionTask.spec, createdAction, actionKeys));
  }
}
async function applyComposeLayout(plan, deps, state) {
  if (plan.layoutPlan.kind === "none") {
    return void 0;
  }
  if (plan.layoutPlan.kind === "explicit") {
    const buildExplicitLayoutPayload = deps.buildExplicitLayoutPayload;
    const setLayout2 = deps.setLayout;
    requireComposeRuntimeDep("buildExplicitLayoutPayload", buildExplicitLayoutPayload, "explicit layout");
    requireComposeRuntimeDep("setLayout", setLayout2, "explicit layout");
    const layoutPayload2 = await buildExplicitLayoutPayload({
      layout: plan.layoutPlan.layout,
      createdByKey: state.keyMap,
      targetUid: plan.gridUid
    });
    return setLayout2({
      target: {
        uid: plan.gridUid
      },
      ...layoutPayload2
    });
  }
  const buildAppendLayoutPayload = deps.buildAppendLayoutPayload;
  const setLayout = deps.setLayout;
  requireComposeRuntimeDep("buildAppendLayoutPayload", buildAppendLayoutPayload, "append layout");
  requireComposeRuntimeDep("setLayout", setLayout, "append layout");
  const layoutPayload = await buildAppendLayoutPayload({
    gridUid: plan.gridUid,
    appendedItemUids: state.blocks.map((block) => block.result.uid)
  });
  return setLayout({
    target: {
      uid: plan.gridUid
    },
    ...layoutPayload
  });
}
async function resolveComposeActionSettings(deps, state, block, action, actionName) {
  if (!hasInlineSettings(action.settings)) {
    return action.settings;
  }
  return deps.resolveActionSettings ? await deps.resolveActionSettings(action.settings || {}, state, block, action, actionName) : action.settings;
}
function requireBlockState(blockKey, state) {
  const matched = state.blocks.find((block) => block.spec.key === blockKey);
  if (!matched) {
    (0, import_errors.throwConflict)(
      `flowSurfaces compose block '${blockKey}' is missing from runtime state`,
      "FLOW_SURFACE_COMPOSE_BLOCK_MISSING"
    );
  }
  return matched;
}
function buildFieldResultSummary(spec, createdField) {
  return {
    key: spec.key,
    uid: createdField.uid,
    ...spec.type ? { type: spec.type } : {},
    ...spec.renderer ? { renderer: spec.renderer } : {},
    fieldPath: spec.fieldPath,
    associationPathName: spec.associationPathName,
    wrapperUid: createdField.wrapperUid,
    fieldUid: createdField.fieldUid,
    innerFieldUid: createdField.innerFieldUid,
    popupPageUid: createdField.popupPageUid,
    popupTabUid: createdField.popupTabUid,
    popupGridUid: createdField.popupGridUid,
    ...spec.target ? { target: spec.target } : {}
  };
}
function buildActionResultSummary(spec, createdAction, actionKeys) {
  return {
    key: spec.key,
    type: spec.type,
    scope: createdAction.scope,
    uid: createdAction.uid,
    parentUid: createdAction.parentUid,
    ...actionKeys
  };
}
function hasInlineSettings(value) {
  return !!value && Object.keys(value).length > 0;
}
function resolveComposeFieldLayoutUid(result) {
  return result.wrapperUid || result.uid;
}
function hasPopupAfterEffect(value) {
  return typeof value !== "undefined";
}
function readComposeFieldTargetKey(target) {
  if (typeof target === "string") {
    const normalized2 = target.trim();
    return normalized2 || void 0;
  }
  if (!target || typeof target !== "object") {
    return void 0;
  }
  const key = typeof target.composeKey === "string" ? target.composeKey : target.key;
  const normalized = typeof key === "string" ? key.trim() : "";
  return normalized || void 0;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  createComposeRuntimeState,
  executeComposeRuntime
});
