/**
 * 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 resolver_exports = {};
__export(resolver_exports, {
  preprocessExpression: () => preprocessExpression,
  resolveJsonTemplate: () => resolveJsonTemplate
});
module.exports = __toCommonJS(resolver_exports);
var import_ses = require("ses");
var import_lodash = __toESM(require("lodash"));
async function resolveJsonTemplate(template, ctx) {
  const compile = async (source) => {
    if (typeof source === "string" && /\{\{.*?\}\}/.test(source)) {
      return await replacePlaceholders(source, ctx);
    }
    if (Array.isArray(source)) return Promise.all(source.map(compile));
    if (source && typeof source === "object") {
      const out = {};
      for (const [k, v] of Object.entries(source)) out[k] = await compile(v);
      return out;
    }
    return source;
  };
  return compile(template);
}
async function replacePlaceholders(input, ctx) {
  const single = input.match(/^\{\{\s*(.+)\s*\}\}$/);
  if (single) {
    const val = await evaluate(single[1], ctx);
    return typeof val === "undefined" ? input : val;
  }
  const regex = /\{\{\s*(.+?)\s*\}\}/g;
  let result = input;
  const matches = [...input.matchAll(regex)];
  for (const [full, inner] of matches) {
    const value = await evaluate(inner, ctx);
    if (typeof value !== "undefined") {
      const replacement = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
      result = result.replace(full, replacement);
    }
  }
  return result;
}
async function evaluate(expr, ctx) {
  try {
    const raw = expr.trim();
    const dotOnly = raw.match(
      /^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\.([a-zA-Z_$][a-zA-Z0-9_$-]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$-]*)*))?$/
    );
    if (dotOnly) {
      const first = dotOnly[1];
      const rest = dotOnly[2];
      const base = await ctx[first];
      if (!rest) return base;
      const resolved = await asyncGetValuesByPath(base, rest);
      if (typeof resolved !== "undefined" || !rest.includes("-")) {
        return resolved;
      }
    }
    const transformed = preprocessExpression(raw);
    const compartment = new Compartment({
      ctx,
      __get: (varName, path) => getAtPath(ctx, varName, path),
      console
    });
    const wrapped = `(async () => { try { return ${transformed}; } catch (e) { return undefined; } })()`;
    return await compartment.evaluate(wrapped);
  } catch (_2) {
    return void 0;
  }
}
async function getAtPath(ctx, varName, path) {
  try {
    let current = await ctx[varName];
    if (!path) return current;
    const norm = String(path || "").replace(/^\./, "");
    const segments = import_lodash.default.toPath(norm);
    for (const seg of segments) {
      if (current == null) return void 0;
      let val = current[seg];
      if (val && typeof val["then"] === "function") {
        val = await val;
      }
      current = val;
    }
    return current;
  } catch (_2) {
    return void 0;
  }
}
async function asyncGetValuesByPath(obj, path, defaultValue) {
  try {
    let currentValue = await obj;
    if (!currentValue) return defaultValue;
    const keys = String(path || "").split(".");
    let result = [];
    let shouldReturnArray = false;
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      if (Array.isArray(currentValue)) {
        shouldReturnArray = true;
        const rest = keys.slice(i).join(".");
        const parts = await Promise.all(currentValue.map((el) => asyncGetValuesByPath(el, rest, defaultValue)));
        for (const p of parts) {
          if (Array.isArray(p)) result.push(...p);
          else if (typeof p !== "undefined") result.push(p);
        }
        break;
      }
      let val = currentValue == null ? void 0 : currentValue[key];
      if (val && typeof val.then === "function") {
        val = await val;
      }
      currentValue = val;
      if (i === keys.length - 1) {
        result.push(currentValue);
      }
    }
    result = result.filter((item) => typeof item !== "undefined");
    if (result.length === 0) return defaultValue;
    if (shouldReturnArray) return result.filter((item) => item !== null);
    return result[0];
  } catch (_2) {
    return defaultValue;
  }
}
function preprocessExpression(expression) {
  let out = "";
  let i = 0;
  const n = expression.length;
  while (i < n) {
    const dotIdx = expression.indexOf("ctx.", i);
    const brkIdx = expression.indexOf("ctx[", i);
    let idx = -1;
    if (dotIdx === -1) idx = brkIdx;
    else if (brkIdx === -1) idx = dotIdx;
    else idx = Math.min(dotIdx, brkIdx);
    if (idx === -1) {
      out += expression.slice(i);
      break;
    }
    out += expression.slice(i, idx);
    let j = idx + 3;
    let varName = null;
    let pathStr = "";
    if (expression[j] === ".") {
      j += 1;
      const varMatch = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(expression.slice(j));
      if (!varMatch) {
        out += "ctx.";
        i = j;
        continue;
      }
      varName = varMatch[0];
      j += varName.length;
    } else if (expression[j] === "[") {
      const m = /^\[("((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')\]/.exec(expression.slice(j));
      if (!m) {
        out += "ctx[";
        i = j;
        continue;
      }
      varName = m[2] ?? m[3];
      j += m[0].length;
    } else {
      out += expression.slice(idx, idx + 3);
      i = idx + 3;
      continue;
    }
    while (j < n) {
      if (expression[j] === ".") {
        const m = /^\.[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(expression.slice(j));
        if (!m) break;
        pathStr += m[0];
        j += m[0].length;
      } else if (expression[j] === "[") {
        const m = /^(\[(?:\d+|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')\])/.exec(expression.slice(j));
        if (!m) break;
        pathStr += m[1];
        j += m[1].length;
      } else {
        break;
      }
    }
    const argPath = pathStr ? `, ${JSON.stringify(pathStr)}` : "";
    out += `(await __get(${JSON.stringify(varName)}${argPath}))`;
    i = j;
  }
  return out;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  preprocessExpression,
  resolveJsonTemplate
});
