import {
  COMMUNICATION_CHANNELS_DELIVER_OUTBOUND_COMMAND_ID
} from "../commands/deliver-outbound-message.js";
import { computeBackoffMs } from "../lib/error-classification.js";
import { COMMUNICATION_CHANNELS_QUEUES, getCommunicationChannelsQueue } from "../lib/queue.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("communication_channels").child({ component: "outbound-delivery" });
const OUTBOUND_DELIVERY_MAX_ATTEMPTS = 3;
const metadata = {
  queue: COMMUNICATION_CHANNELS_QUEUES.outbound,
  id: "communication_channels:outbound-delivery",
  concurrency: 10
};
async function handle(job, ctx) {
  const { messageId, scope, attempt = 1, forceCredentialRefresh } = job.payload;
  const commandBus = ctx.resolve("commandBus");
  const containerProxy = { resolve: ctx.resolve.bind(ctx) };
  const commandCtx = {
    container: containerProxy,
    auth: null,
    organizationScope: null,
    selectedOrganizationId: scope.organizationId ?? null,
    organizationIds: scope.organizationId ? [scope.organizationId] : null
  };
  let outcome;
  try {
    const { result } = await commandBus.execute(
      COMMUNICATION_CHANNELS_DELIVER_OUTBOUND_COMMAND_ID,
      {
        input: { messageId, scope, forceCredentialRefresh },
        ctx: commandCtx
      }
    );
    outcome = result;
  } catch (err) {
    const errorMessage = err instanceof Error ? err.message : String(err);
    logger.warn("command threw during delivery attempt", { attempt, messageId, reason: errorMessage });
    if (attempt < OUTBOUND_DELIVERY_MAX_ATTEMPTS) {
      await reenqueue(job.payload, attempt);
      return;
    }
    throw err;
  }
  switch (outcome.status) {
    case "delivered":
    case "already_delivered":
    case "no_channel_link":
      return;
    case "failed": {
      if (outcome.requiresReauth && !forceCredentialRefresh && attempt < OUTBOUND_DELIVERY_MAX_ATTEMPTS) {
        logger.warn("reauth failure; retrying once with a forced credential refresh", { attempt, messageId, providerKey: outcome.providerKey, reason: outcome.error });
        await reenqueue({ ...job.payload, forceCredentialRefresh: true }, attempt);
        return;
      }
      if (outcome.transient && attempt < OUTBOUND_DELIVERY_MAX_ATTEMPTS) {
        logger.warn("transient delivery failure; re-enqueueing", { attempt, messageId, providerKey: outcome.providerKey, reason: outcome.error });
        await reenqueue(job.payload, attempt);
        return;
      }
      logger.error("giving up on message delivery", { messageId, attempt, providerKey: outcome.providerKey, reason: outcome.error });
      return;
    }
  }
}
async function reenqueue(payload, attempt) {
  const next = {
    ...payload,
    attempt: attempt + 1
  };
  const delayMs = computeBackoffMs(attempt);
  const queue = getCommunicationChannelsQueue(COMMUNICATION_CHANNELS_QUEUES.outbound);
  await queue.enqueue(next, { delayMs });
}
export {
  OUTBOUND_DELIVERY_MAX_ATTEMPTS,
  handle as default,
  metadata
};
//# sourceMappingURL=outbound-delivery.js.map
