import { defineAsyncComponent } from "vue";
import { Effect } from "effect";
import { toast } from "vue-sonner";
import { defineRegistry } from "../../../share/define-registry.js";
import { dispatchTriggers } from "../../../share/event-bus.js";
const schemaModules = import.meta.glob(
  "../buttons/*/*/schema.{ts,js}",
  { eager: true, exhaustive: true }
);
const configModuleLoaders = import.meta.glob(
  "../buttons/*/*/config.vue",
  { exhaustive: true }
);
const runtimeModuleLoaders = import.meta.glob(
  "../buttons/*/*/runtime.vue",
  { exhaustive: true }
);
const configModules = Object.fromEntries(
  Object.entries(configModuleLoaders).map(([path, loader]) => [
    path,
    defineAsyncComponent(loader)
  ])
);
const runtimeModules = Object.fromEntries(
  Object.entries(runtimeModuleLoaders).map(([path, loader]) => [
    path,
    defineAsyncComponent(loader)
  ])
);
const registry = defineRegistry({
  hostName: "shwfed-actions",
  dirSegment: "buttons",
  schemaModules,
  configModules,
  runtimeModules,
  // A button is deprecated when its schema declares `metadata.deprecated`
  // (an explicit, possibly cross-type replacement note), or when a newer
  // `compatibilityDate` of the same `type` exists (the date-versioned rule
  // shared with form). Either way the inspector shows the migration hint.
  deriveEntryExtras: (drafts) => {
    const latestByType = /* @__PURE__ */ new Map();
    for (const d of drafts) {
      const prev = latestByType.get(d.type);
      if (!prev || d.compatibilityDate > prev) latestByType.set(d.type, d.compatibilityDate);
    }
    return (draft) => {
      const note = draft.module.metadata.deprecated;
      if (note) return { deprecated: true, deprecationNote: note };
      if (draft.compatibilityDate < latestByType.get(draft.type)) {
        return {
          deprecated: true,
          deprecationNote: `\u5DF2\u88AB\u66F4\u65B0\u7248\u672C ${latestByType.get(draft.type)} \u53D6\u4EE3\u3002`
        };
      }
      return { deprecated: false };
    };
  }
});
export const BUTTONS = registry.ENTRIES.map((e) => ({
  type: e.type,
  compatibilityDate: e.compatibilityDate,
  metadata: e.module.metadata,
  schema: e.module.schema,
  config: e.config,
  runtime: e.runtime,
  deprecated: e.deprecated,
  ...e.deprecationNote !== void 0 ? { deprecationNote: e.deprecationNote } : {}
}));
export function allButtonSchemas(configure) {
  return BUTTONS.map((entry) => entry.schema(configure).annotations({
    identifier: `${entry.type}@${entry.compatibilityDate}`
  }));
}
export function findButton(type, compatibilityDate) {
  return BUTTONS.find((a) => a.type === type && a.compatibilityDate === compatibilityDate);
}
const itemSchemaModules = import.meta.glob(
  "../items/*/*/schema.{ts,js}",
  { eager: true, exhaustive: true }
);
const itemConfigModuleLoaders = import.meta.glob(
  "../items/*/*/config.vue",
  { exhaustive: true }
);
const itemRuntimeModuleLoaders = import.meta.glob(
  "../items/*/*/runtime.vue",
  { exhaustive: true }
);
const itemConfigModules = Object.fromEntries(
  Object.entries(itemConfigModuleLoaders).map(([path, loader]) => [
    path,
    defineAsyncComponent(loader)
  ])
);
const itemRuntimeModules = Object.fromEntries(
  Object.entries(itemRuntimeModuleLoaders).map(([path, loader]) => [
    path,
    defineAsyncComponent(loader)
  ])
);
const itemRegistry = defineRegistry({
  hostName: "shwfed-actions",
  dirSegment: "items",
  schemaModules: itemSchemaModules,
  configModules: itemConfigModules,
  runtimeModules: itemRuntimeModules
});
export const ITEMS = itemRegistry.ENTRIES.map((e) => ({
  type: e.type,
  compatibilityDate: e.compatibilityDate,
  metadata: e.module.metadata,
  schema: e.module.schema,
  config: e.config,
  runtime: e.runtime
}));
export function allItemSchemas(configure) {
  return ITEMS.map((entry) => entry.schema(configure).annotations({
    identifier: `${entry.type}@${entry.compatibilityDate}`
  }));
}
export function findItem(type, compatibilityDate) {
  return ITEMS.find((i) => i.type === type && i.compatibilityDate === compatibilityDate);
}
const INTERPOLATION_RE = /\{\{(.*?)\}\}/gs;
export function interpolateMarkdown(source, $cel) {
  return source.replace(INTERPOLATION_RE, (_, expr) => {
    const trimmed = expr.trim();
    if (trimmed.length === 0) return "{{ }}";
    try {
      return stringifyCelResult(Effect.runSync($cel(trimmed)));
    } catch {
      return `{{${expr}}}`;
    }
  });
}
function stringifyCelResult(value) {
  if (value === null || value === void 0) return "";
  if (typeof value === "object") return JSON.stringify(value);
  return String(value);
}
const TOAST_STYLES = /* @__PURE__ */ new Set(["success", "error", "warning", "info"]);
export function executeHttpRequest(expression, $cel, outcome = {}) {
  const { messageExpression, resultExpression, channel, triggers } = outcome;
  const request = Effect.flatMap(
    $cel(expression),
    (builder) => builder.json()
  );
  return Effect.flatMap(request, (body) => {
    const context = { json: body };
    const result = resultExpression === void 0 ? Effect.succeed("success") : Effect.map($cel(resultExpression, context), (s) => TOAST_STYLES.has(s) ? s : "success");
    return Effect.flatMap(result, (kind) => {
      const toasted = messageExpression === void 0 ? Effect.void : Effect.flatMap(
        $cel(messageExpression, context),
        (message) => Effect.sync(() => toast[kind](message))
      );
      return Effect.andThen(toasted, dispatchTriggers(channel, triggers?.[kind]));
    });
  });
}
