/**
 * 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 context_exports = {};
__export(context_exports, {
  buildFlowSurfaceContextResponse: () => buildFlowSurfaceContextResponse,
  isBareFlowContextPath: () => isBareFlowContextPath
});
module.exports = __toCommonJS(context_exports);
const RELATION_FIELD_TYPES = /* @__PURE__ */ new Set(["belongsTo", "hasOne", "hasMany", "belongsToMany", "belongsToArray"]);
const NUMERIC_FIELD_TYPES = /* @__PURE__ */ new Set(["integer", "float", "double", "decimal"]);
const BARE_FLOW_CONTEXT_PATH_RE = /^[A-Za-z_][A-Za-z0-9_-]*(\.[A-Za-z_][A-Za-z0-9_-]*)*$/;
function isBareFlowContextPath(path) {
  return BARE_FLOW_CONTEXT_PATH_RE.test(path);
}
function getCollectionFields(collection) {
  if (!collection) {
    return [];
  }
  if (Array.isArray(collection.fields)) {
    return collection.fields;
  }
  if (collection.fields instanceof Map) {
    return Array.from(collection.fields.values());
  }
  if (collection.fields && typeof collection.fields === "object") {
    return Object.values(collection.fields);
  }
  if (typeof collection.getFields === "function") {
    return collection.getFields() || [];
  }
  return [];
}
function getCollectionCycleKey(collection) {
  if (!collection) {
    return void 0;
  }
  return `collection:${collection.dataSourceKey || "main"}:${collection.name || collection.title || "unknown"}`;
}
function getFieldType(field) {
  const fieldType = field == null ? void 0 : field.type;
  if (RELATION_FIELD_TYPES.has(fieldType)) {
    return "object";
  }
  if (NUMERIC_FIELD_TYPES.has(fieldType)) {
    return "number";
  }
  switch (fieldType) {
    case "boolean":
      return "boolean";
    case "json":
      return "object";
    case "array":
      return "array";
    default:
      return "string";
  }
}
function getFieldTargetCollection(field) {
  const targetCollection = typeof (field == null ? void 0 : field.targetCollection) === "function" ? field.targetCollection() : field == null ? void 0 : field.targetCollection;
  return targetCollection && typeof targetCollection === "object" ? targetCollection : null;
}
function isAssociationField(field, targetCollection) {
  if (typeof (field == null ? void 0 : field.isAssociationField) === "function") {
    return !!field.isAssociationField();
  }
  return !!targetCollection || RELATION_FIELD_TYPES.has(field == null ? void 0 : field.type);
}
function createCollectionFieldSpec(field) {
  const targetCollection = getFieldTargetCollection(field);
  return {
    title: (field == null ? void 0 : field.title) || (field == null ? void 0 : field.name),
    type: getFieldType(field),
    interface: field == null ? void 0 : field.interface,
    ...isAssociationField(field, targetCollection) && targetCollection ? {
      cycleKey: getCollectionCycleKey(targetCollection),
      properties: () => buildCollectionProperties(targetCollection)
    } : {}
  };
}
function buildCollectionProperties(collection) {
  const properties = {};
  for (const field of getCollectionFields(collection)) {
    if (!(field == null ? void 0 : field.name)) {
      continue;
    }
    properties[field.name] = createCollectionFieldSpec(field);
  }
  return properties;
}
function createCollectionSpec(collection, title) {
  if (!collection) {
    return null;
  }
  return {
    title,
    type: "object",
    cycleKey: getCollectionCycleKey(collection),
    properties: () => buildCollectionProperties(collection)
  };
}
function createItemSpec(currentCollection, parentSpec) {
  if (!currentCollection) {
    return null;
  }
  return {
    title: "Current item",
    type: "object",
    properties: () => {
      const properties = {
        index: {
          title: "Index (starts from 0)",
          type: "number"
        },
        length: {
          title: "Total count",
          type: "number"
        }
      };
      const valueSpec = createCollectionSpec(currentCollection, "Attributes");
      if (valueSpec) {
        properties.value = valueSpec;
      }
      if (parentSpec) {
        properties.parentItem = parentSpec;
      }
      return properties;
    }
  };
}
function buildItemChainSpec(collections, rootCollection) {
  if (!collections.length) {
    return null;
  }
  let parentSpec;
  if (rootCollection) {
    parentSpec = {
      title: "Parent item",
      type: "object",
      properties: () => {
        const properties = {
          index: {
            title: "Index (starts from 0)",
            type: "number"
          },
          length: {
            title: "Total count",
            type: "number"
          }
        };
        const valueSpec = createCollectionSpec(rootCollection, "Attributes");
        if (valueSpec) {
          properties.value = valueSpec;
        }
        return properties;
      }
    };
  }
  for (let index = collections.length - 1; index >= 0; index -= 1) {
    const itemSpec = createItemSpec(collections[index], parentSpec);
    if (!itemSpec) {
      continue;
    }
    if (parentSpec) {
      itemSpec.title = "Parent item";
    }
    parentSpec = itemSpec;
  }
  if (!parentSpec) {
    return null;
  }
  parentSpec.title = "Current item";
  return parentSpec;
}
function buildPopupChainSpec(levels) {
  if (!levels.length) {
    return null;
  }
  const currentLevel = levels[0] || {};
  const parentLevel = levels[1] || null;
  return {
    title: "Current popup",
    type: "object",
    properties: () => {
      const properties = {
        uid: {
          title: "Popup uid",
          type: "string"
        }
      };
      const recordSpec = createCollectionSpec(currentLevel.recordCollection, "Current popup record");
      if (recordSpec) {
        properties.record = recordSpec;
      }
      const sourceRecordSpec = createCollectionSpec(currentLevel.sourceRecordCollection, "Current popup parent record");
      if (sourceRecordSpec) {
        properties.sourceRecord = sourceRecordSpec;
      }
      if (parentLevel) {
        properties.parent = {
          title: "Parent popup",
          type: "object",
          properties: () => {
            const parentProperties = {
              uid: {
                title: "Popup uid",
                type: "string"
              }
            };
            const parentRecordSpec = createCollectionSpec(parentLevel.recordCollection, "Popup record");
            if (parentRecordSpec) {
              parentProperties.record = parentRecordSpec;
            }
            return parentProperties;
          }
        };
      }
      return properties;
    }
  };
}
function buildChartQueryOutputsSpec(outputs) {
  if (!outputs.length) {
    return null;
  }
  return {
    title: "Builder query outputs",
    type: "object",
    properties: () => Object.fromEntries(
      outputs.map((output) => {
        const fieldValue = Array.isArray(output.field) ? output.field.join(".") : output.field;
        const descSegments = [
          output.source === "sql" ? "SQL preview output" : output.kind === "measure" ? "Measure output" : output.kind === "dimension" ? "Dimension output" : "",
          fieldValue ? `field=${fieldValue}` : "",
          output.aggregation ? `aggregation=${output.aggregation}` : "",
          output.format ? `format=${output.format}` : ""
        ].filter(Boolean);
        return [
          output.alias,
          {
            title: output.alias,
            type: output.type || "string",
            ...descSegments.length ? { description: descSegments.join("; ") } : {}
          }
        ];
      })
    )
  };
}
function buildChartAliasesSpec(aliases) {
  if (!aliases.length) {
    return null;
  }
  return {
    title: "Builder query aliases",
    type: "object",
    properties: () => Object.fromEntries(
      aliases.map((alias) => [
        alias,
        {
          title: alias,
          type: "string",
          description: "Builder query output alias that can be used by visual.mappings.*. Do not assume it is valid for query.sorting.field; aggregated measure outputs and custom measure aliases remain unsupported there."
        }
      ])
    )
  };
}
function buildChartSupportedMappingsSpec(supportedMappings) {
  if (!supportedMappings || !Object.keys(supportedMappings).length) {
    return null;
  }
  return {
    title: "Supported mappings by visual type",
    type: "object",
    properties: () => Object.fromEntries(
      Object.entries(supportedMappings).map(([visualType, support]) => [
        visualType,
        {
          title: visualType,
          type: "object",
          properties: () => Object.fromEntries(
            (support.allowed || []).map((mappingKey) => [
              mappingKey,
              {
                title: mappingKey,
                type: "string",
                description: (support.required || []).includes(mappingKey) ? "Required mapping key" : "Optional mapping key"
              }
            ])
          )
        }
      ])
    )
  };
}
function buildChartSupportedStylesSpec(supportedStyles) {
  if (!supportedStyles || !Object.keys(supportedStyles).length) {
    return null;
  }
  return {
    title: "Supported style keys by visual type",
    type: "object",
    properties: () => Object.fromEntries(
      Object.entries(supportedStyles).map(([visualType, styles]) => [
        visualType,
        {
          title: visualType,
          type: "object",
          properties: () => Object.fromEntries(
            Object.entries(styles || {}).map(([styleKey, support]) => {
              var _a;
              return [
                styleKey,
                {
                  title: styleKey,
                  type: support.type,
                  ...support.description ? { description: support.description } : {},
                  ...((_a = support.enumValues) == null ? void 0 : _a.length) ? { enumValues: [...support.enumValues] } : {},
                  ...typeof support.min !== "undefined" ? { min: support.min } : {},
                  ...typeof support.max !== "undefined" ? { max: support.max } : {}
                }
              ];
            })
          )
        }
      ])
    )
  };
}
function buildChartSupportedVisualTypesSpec(types) {
  if (!types.length) {
    return null;
  }
  return {
    title: "Supported visual types",
    type: "object",
    properties: () => Object.fromEntries(
      types.map((type) => [
        type,
        {
          title: type,
          type: "string",
          description: "Supported chart visual.type value"
        }
      ])
    )
  };
}
function buildChartHintListSpec(title, hints) {
  if (!hints.length) {
    return null;
  }
  return {
    title,
    type: "object",
    properties: () => Object.fromEntries(
      hints.map((hint) => [
        hint.key,
        {
          title: hint.title,
          type: "string",
          description: hint.description
        }
      ])
    )
  };
}
function createChartSpec(chart) {
  if (!chart) {
    return null;
  }
  return {
    title: "Chart helpers",
    type: "object",
    properties: () => {
      const properties = {};
      const queryOutputsSpec = buildChartQueryOutputsSpec(chart.queryOutputs || []);
      if (queryOutputsSpec) {
        properties.queryOutputs = queryOutputsSpec;
      }
      const aliasesSpec = buildChartAliasesSpec(chart.aliases || []);
      if (aliasesSpec) {
        properties.aliases = aliasesSpec;
      }
      const supportedMappingsSpec = buildChartSupportedMappingsSpec(chart.supportedMappings);
      if (supportedMappingsSpec) {
        properties.supportedMappings = supportedMappingsSpec;
      }
      const supportedStylesSpec = buildChartSupportedStylesSpec(chart.supportedStyles);
      if (supportedStylesSpec) {
        properties.supportedStyles = supportedStylesSpec;
      }
      const supportedVisualTypesSpec = buildChartSupportedVisualTypesSpec(chart.supportedVisualTypes || []);
      if (supportedVisualTypesSpec) {
        properties.supportedVisualTypes = supportedVisualTypesSpec;
      }
      const safeDefaultsSpec = buildChartHintListSpec("Safe defaults", chart.safeDefaults || []);
      if (safeDefaultsSpec) {
        properties.safeDefaults = safeDefaultsSpec;
      }
      const riskyPatternsSpec = buildChartHintListSpec("Risky patterns", chart.riskyPatterns || []);
      if (riskyPatternsSpec) {
        properties.riskyPatterns = riskyPatternsSpec;
      }
      const unsupportedPatternsSpec = buildChartHintListSpec("Unsupported patterns", chart.unsupportedPatterns || []);
      if (unsupportedPatternsSpec) {
        properties.unsupportedPatterns = unsupportedPatternsSpec;
      }
      return properties;
    }
  };
}
const DEVICE_TYPE_ENUM_VALUES = ["computer", "mobile", "tablet", "smarttv", "console", "wearable", "embedded"];
function createPrimitiveSpec(title, type, options = {}) {
  return {
    title,
    type,
    ...options
  };
}
function createUserSpec(userCollection) {
  const fallbackProperties = () => ({
    id: createPrimitiveSpec("ID", "number", { interface: "id" }),
    nickname: createPrimitiveSpec("Nickname", "string"),
    username: createPrimitiveSpec("Username", "string"),
    email: createPrimitiveSpec("Email", "string"),
    roles: createPrimitiveSpec("Roles", "array")
  });
  return {
    title: "Current user",
    type: "object",
    ...userCollection ? { cycleKey: getCollectionCycleKey(userCollection) } : {},
    properties: () => ({
      ...fallbackProperties(),
      ...buildCollectionProperties(userCollection)
    })
  };
}
function createAuthSpec(userCollection) {
  return {
    title: "Authentication",
    type: "object",
    properties: () => ({
      roleName: createPrimitiveSpec("Current role", "string"),
      locale: createPrimitiveSpec("Current language", "string"),
      token: createPrimitiveSpec("API Token", "string"),
      user: createUserSpec(userCollection)
    })
  };
}
function createUrlSearchParamsSpec() {
  return {
    title: "URL search params",
    type: "object",
    disabledReason: "The value of this variable is derived from the query string of the page URL. It is available when the page URL has query parameters.",
    dynamicProperties: createPrimitiveSpec("URL search param", "string")
  };
}
function createLocationSpec() {
  return {
    title: "Current location",
    type: "object",
    properties: () => ({
      pathname: createPrimitiveSpec("Pathname", "string"),
      search: createPrimitiveSpec("Search", "string"),
      hash: createPrimitiveSpec("Hash", "string")
    })
  };
}
function createSpecMap(input) {
  const specs = {};
  specs.user = createUserSpec(input.userCollection);
  specs.role = createPrimitiveSpec("Current role", "string");
  specs.locale = createPrimitiveSpec("Current language", "string");
  specs.token = createPrimitiveSpec("API Token", "string");
  specs.auth = createAuthSpec(input.userCollection);
  specs.urlSearchParams = createUrlSearchParamsSpec();
  specs.location = createLocationSpec();
  specs.deviceType = createPrimitiveSpec("Current device type", "string", {
    interface: "select",
    enumValues: DEVICE_TYPE_ENUM_VALUES,
    description: "Current device type (computer/mobile/tablet/...)."
  });
  const collectionSpec = createCollectionSpec(input.collection, "Current collection");
  if (collectionSpec) {
    specs.collection = collectionSpec;
  }
  const recordSpec = createCollectionSpec(input.recordCollection, "Current record");
  if (recordSpec) {
    specs.record = recordSpec;
  }
  const formValuesSpec = createCollectionSpec(input.formValuesCollection, "Current form");
  if (formValuesSpec) {
    specs.formValues = formValuesSpec;
  }
  const itemSpec = buildItemChainSpec(input.itemCollections || [], input.itemRootCollection);
  if (itemSpec) {
    specs.item = itemSpec;
  }
  const popupSpec = buildPopupChainSpec(input.popupLevels || []);
  if (popupSpec) {
    specs.popup = popupSpec;
  }
  const chartSpec = createChartSpec(input.chart);
  if (chartSpec) {
    specs.chart = chartSpec;
  }
  return specs;
}
function materializeSpecNode(node, depth, maxDepth, visited) {
  const output = {};
  if (typeof node.title !== "undefined") {
    output.title = node.title;
  }
  if (typeof node.type !== "undefined") {
    output.type = node.type;
  }
  if (typeof node.interface !== "undefined") {
    output.interface = node.interface;
  }
  if (typeof node.description !== "undefined") {
    output.description = node.description;
  }
  if (Array.isArray(node.enumValues) && node.enumValues.length) {
    output.enumValues = [...node.enumValues];
  }
  if (typeof node.min !== "undefined") {
    output.min = node.min;
  }
  if (typeof node.max !== "undefined") {
    output.max = node.max;
  }
  if (typeof node.disabled !== "undefined") {
    output.disabled = node.disabled;
  }
  if (typeof node.disabledReason !== "undefined") {
    output.disabledReason = node.disabledReason;
  }
  if (node.dynamicProperties) {
    output.dynamicProperties = materializeSpecNode(node.dynamicProperties, depth + 1, maxDepth, visited);
  }
  if (depth >= maxDepth || typeof node.properties !== "function") {
    return output;
  }
  if (node.cycleKey && visited.has(node.cycleKey)) {
    return output;
  }
  const nextVisited = new Set(visited);
  if (node.cycleKey) {
    nextVisited.add(node.cycleKey);
  }
  const properties = node.properties();
  const propertyEntries = Object.entries(properties || {});
  if (!propertyEntries.length) {
    return output;
  }
  output.properties = Object.fromEntries(
    propertyEntries.map(([key, child]) => [key, materializeSpecNode(child, depth + 1, maxDepth, nextVisited)])
  );
  return output;
}
function resolveSpecAtPath(specs, path) {
  var _a;
  const segments = String(path || "").split(".").map((segment) => segment.trim()).filter(Boolean);
  if (!segments.length) {
    return void 0;
  }
  let current = specs[segments[0]];
  if (!current) {
    return void 0;
  }
  for (let index = 1; index < segments.length; index += 1) {
    const properties = (_a = current.properties) == null ? void 0 : _a.call(current);
    const next = properties == null ? void 0 : properties[segments[index]];
    if (next) {
      current = next;
      continue;
    }
    if (current.dynamicProperties) {
      current = current.dynamicProperties;
      continue;
    }
    return void 0;
  }
  return current;
}
function buildFlowSurfaceContextResponse(input) {
  const maxDepthRaw = input.maxDepth ?? 3;
  const maxDepth = Number.isFinite(maxDepthRaw) ? Math.max(1, Math.floor(maxDepthRaw)) : 3;
  const specs = createSpecMap(input.semantic);
  if (input.path) {
    const targetSpec = resolveSpecAtPath(specs, input.path);
    return {
      vars: targetSpec ? { [input.path]: materializeSpecNode(targetSpec, 1, maxDepth, /* @__PURE__ */ new Set()) } : {}
    };
  }
  return {
    vars: Object.fromEntries(
      Object.entries(specs).map(([key, spec]) => [key, materializeSpecNode(spec, 1, maxDepth, /* @__PURE__ */ new Set())])
    )
  };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  buildFlowSurfaceContextResponse,
  isBareFlowContextPath
});
