import { Either, Schema } from "effect";
import { Environment } from "../vendor/cel-js/lib/index.js";
import { CelError } from "../vendor/cel-js/lib/errors.js";
import { Locale } from "./locale.js";
export const HttpRequestResult = (t) => t === "HttpRequest" || t === "optional<HttpRequest>" || t === "optional<dyn>" || t === "dyn";
function matchesScalarType(actual, expected) {
  if (expected === "dyn" || actual === "dyn") return true;
  if (actual === expected) return true;
  if (actual.startsWith(`${expected}<`)) return true;
  if (actual === `optional<${expected}>` || actual === "optional<dyn>") return true;
  if (actual.startsWith(`optional<${expected}<`)) return true;
  return false;
}
function matchesResultType(actual, expected) {
  if (typeof expected === "string") return matchesScalarType(actual, expected);
  if (Array.isArray(expected)) return expected.some((e) => matchesScalarType(actual, e));
  return expected(actual);
}
function formatExpectedType(expected) {
  if (typeof expected === "string") return expected;
  if (Array.isArray(expected)) return expected.join(" | ");
  return "(\u81EA\u5B9A\u4E49)";
}
function registerScopeAddressVar(env) {
  env.registerVariable("__scopes__", "map<string, dyn>", {
    label: "\u8DE8\u5C42\u4F5C\u7528\u57DF",
    description: "\u6309 UUID \u5BFB\u5740\u88AB\u906E\u853D\u7684\u7956\u5148\u4F5C\u7528\u57DF"
  });
}
export function evaluateExpression(env, expression, resultType) {
  const result = env.check(expression);
  if (Either.isLeft(result)) {
    const error = result.left;
    const summary = error instanceof CelError ? error.summary : String(error);
    return `\u8868\u8FBE\u5F0F\u65E0\u6548\uFF1A${summary}`;
  }
  if (resultType) {
    const actualType = result.right;
    if (!matchesResultType(actualType, resultType)) {
      return `\u8868\u8FBE\u5F0F\u8FD4\u56DE\u7C7B\u578B\u4E0D\u5339\u914D\uFF0C\u671F\u671B ${formatExpectedType(resultType)}\uFF0C\u5B9E\u9645\u4E3A ${actualType}`;
    }
  }
  return null;
}
export function buildCheckEnvironment(vars, options) {
  const env = new Environment({
    unlistedVariablesAreDyn: options?.unlistedVariablesAreDyn ?? false
  });
  registerScopeAddressVar(env);
  for (const { name, type } of vars) {
    if (name === "__scopes__") continue;
    env.registerVariable(name, type);
  }
  return env;
}
function buildDescription(baseline, env, resultType) {
  const defs = env.getDefinitions();
  const baselineVarNames = new Set(baseline.variables.map((v) => v.name));
  const baselineFnSigs = new Set(baseline.functions.map((f) => f.signature));
  const parts = ["CEL expression."];
  const userVars = defs.variables.filter((v) => !baselineVarNames.has(v.name));
  if (userVars.length > 0) {
    const vars = userVars.map((v) => v.description ? `${v.name} (${v.type}): ${v.description}` : `${v.name} (${v.type})`).join(", ");
    parts.push(`Available variables: ${vars}.`);
  }
  const userFns = defs.functions.filter((f) => !baselineFnSigs.has(f.signature));
  if (userFns.length > 0) {
    const fns = userFns.map((f) => {
      const base = f.signature;
      return f.description ? `${base}: ${f.description}` : base;
    }).join(", ");
    parts.push(`Available functions: ${fns}.`);
  }
  if (resultType) {
    parts.push(`Expected return type: ${formatExpectedType(resultType)}.`);
  }
  return parts.join(" ");
}
export function Expression(options) {
  const env = new Environment({
    unlistedVariablesAreDyn: options.unlistedVariablesAreDyn ?? false
  });
  registerScopeAddressVar(env);
  const baseline = env.getDefinitions();
  options.configure(env);
  const description = buildDescription(baseline, env, options.resultType);
  return Schema.String.pipe(
    Schema.filter(
      (expression) => evaluateExpression(env, expression, options.resultType) ?? true,
      {
        title: "CEL Expression",
        description
      }
    )
  );
}
const INTERPOLATION_RE = /\{\{(.*?)\}\}/gs;
export function Markdown(options) {
  const env = new Environment({ unlistedVariablesAreDyn: false });
  registerScopeAddressVar(env);
  const baseline = env.getDefinitions();
  options.configure(env);
  const description = `Markdown with CEL interpolation via {{ expression }}. ${buildDescription(baseline, env).slice("CEL expression. ".length)}`;
  return Schema.String.pipe(
    Schema.filter(
      (input) => {
        let match;
        INTERPOLATION_RE.lastIndex = 0;
        while ((match = INTERPOLATION_RE.exec(input)) !== null) {
          const expr = match[1].trim();
          if (expr.length === 0) {
            return `{{ }} \u63D2\u503C\u8868\u8FBE\u5F0F\u4E0D\u80FD\u4E3A\u7A7A`;
          }
          const result = env.check(expr);
          if (Either.isLeft(result)) {
            const error = result.left;
            const summary = error instanceof CelError ? error.summary : String(error);
            return `{{ ${expr} }} \u8868\u8FBE\u5F0F\u65E0\u6548\uFF1A${summary}`;
          }
        }
        return true;
      },
      {
        title: "Markdown",
        description
      }
    )
  );
}
export function LocaleMarkdown(options) {
  const env = new Environment({ unlistedVariablesAreDyn: false });
  registerScopeAddressVar(env);
  const baseline = env.getDefinitions();
  options.configure(env);
  const description = `Locale with Markdown CEL interpolation via {{ expression }}. ${buildDescription(baseline, env).slice("CEL expression. ".length)}`;
  return Locale.pipe(
    Schema.filter(
      (items) => {
        for (const item of items) {
          const input = item.message;
          let match;
          INTERPOLATION_RE.lastIndex = 0;
          while ((match = INTERPOLATION_RE.exec(input)) !== null) {
            const expr = match[1].trim();
            if (expr.length === 0) {
              return `[${item.locale}] {{ }} \u63D2\u503C\u8868\u8FBE\u5F0F\u4E0D\u80FD\u4E3A\u7A7A`;
            }
            const result = env.check(expr);
            if (Either.isLeft(result)) {
              const error = result.left;
              const summary = error instanceof CelError ? error.summary : String(error);
              return `[${item.locale}] {{ ${expr} }} \u8868\u8FBE\u5F0F\u65E0\u6548\uFF1A${summary}`;
            }
          }
        }
        return true;
      },
      {
        title: "LocaleMarkdown",
        description
      }
    )
  );
}
