import { computed, inject, provide, shallowRef } from "vue";
import { Effect, Schema } from "effect";
export const Trigger = Schema.Struct({
  // Additive + optional like `compatibilityDate`/`params` below, so every
  // pre-existing `{ target, operation }` trigger keeps loading. Minted by the
  // trigger editor on add; it is the address under which this step's output is
  // published for later steps (`steps["<id>"]`), so it must survive reorders —
  // which the list index, the only other row identity, does not.
  id: Schema.optional(Schema.UUID.annotations({
    description: '\u89E6\u53D1\u884C\u7684\u7A33\u5B9A\u6807\u8BC6\uFF0C\u540E\u7EED\u6B65\u9AA4\u7ECF steps["<id>"] \u5F15\u7528\u672C\u6B65\u8F93\u51FA'
  })),
  target: Schema.UUID.annotations({
    description: "\u76EE\u6807\u7956\u5148\u5B9E\u4F8B\u7684 ID"
  }),
  operation: Schema.String.annotations({
    description: "\u76EE\u6807\u7EC4\u4EF6\u80FD\u529B\u6E05\u5355\u4E2D\u7684\u64CD\u4F5C ID"
  }),
  // Parameterized operations carry their version + configured params on the
  // row. Both are optional and absent for param-less ops (close / validate /
  // refetch), so every pre-existing `{ target, operation }` trigger stays
  // valid — this additive shape is what keeps stored configs loading. `params`
  // is opaque here: it is validated against the *target operation's* own
  // schema (a cross-reference `target → type → operation`) in the trigger
  // editor, not by this row schema, since the schema lives on the host's
  // manifest rather than on the row.
  compatibilityDate: Schema.optional(Schema.String.annotations({
    description: "\u53C2\u6570\u5316\u64CD\u4F5C\u7684\u517C\u5BB9\u6027\u65E5\u671F\uFF1B\u65E0\u53C2\u64CD\u4F5C\u7701\u7565"
  })),
  params: Schema.optional(Schema.Unknown.annotations({
    description: "\u64CD\u4F5C\u53C2\u6570\uFF0C\u6309\u76EE\u6807\u64CD\u4F5C\u7684 schema \u6821\u9A8C"
  }))
}).annotations({
  title: "Trigger",
  description: "\u4E00\u6761\u5411\u4E0A\u5192\u6CE1\u7684\u64CD\u4F5C\u8BF7\u6C42"
});
export const Triggers = Schema.Array(Trigger).annotations({
  title: "\u89E6\u53D1\u64CD\u4F5C",
  description: "\u6309\u5217\u8868\u987A\u5E8F\u6267\u884C"
});
export const EVENT_CHANNEL_KEY = Symbol("shwfed/event-channel");
export function createEventChannel(instanceId, operations, parent) {
  return {
    dispatch(request) {
      const handled = request.target === instanceId ? operations[request.operation]?.(request.params, request.cel, request.step) ?? Effect.void : Effect.void;
      return parent ? Effect.andThen(handled, parent.dispatch(request)) : handled;
    }
  };
}
export function provideEventTarget(instanceId, operations) {
  const parent = inject(EVENT_CHANNEL_KEY, void 0);
  provide(EVENT_CHANNEL_KEY, createEventChannel(instanceId, operations, parent));
}
export function useEventChannel() {
  return inject(EVENT_CHANNEL_KEY, void 0);
}
export function dispatchTriggers(channel, triggers, cel) {
  if (!channel || !triggers || triggers.length === 0) return Effect.void;
  return Effect.suspend(() => {
    const outputs = {};
    return Effect.forEach(
      triggers,
      (trigger) => channel.dispatch({
        target: trigger.target,
        operation: trigger.operation,
        params: trigger.params,
        cel,
        step: {
          outputs: () => outputs,
          publish: (output) => {
            if (trigger.id) outputs[trigger.id] = output;
          }
        }
      }),
      { discard: true }
    );
  });
}
const EVENT_ANCESTRY_KEY = Symbol("shwfed/event-ancestry");
export function provideEventAncestor(ancestor) {
  const parent = inject(EVENT_ANCESTRY_KEY, void 0);
  provide(
    EVENT_ANCESTRY_KEY,
    computed(() => {
      const chain = parent?.value ?? [];
      return ancestor.value ? [ancestor.value, ...chain] : chain;
    })
  );
}
export function useEventAncestry() {
  return inject(EVENT_ANCESTRY_KEY, void 0) ?? shallowRef([]);
}
