import type Redis from "ioredis";
import type { ServerEventEnvelope } from "@slackwsh/contracts";

export const MESSAGING_EVENTS_CHANNEL = "messaging:events";

export interface RoomEvent {
  room: string; // e.g. `ch:${channelId}` or `ws:${workspaceId}`
  event: ServerEventEnvelope;
}

/**
 * The bridge between writes (apps/api, apps/gateway) and realtime fanout.
 * Every mutation publishes here after its transaction commits; every
 * gateway node subscribes and re-emits into the named Socket.IO room. This
 * is deliberately the *only* thing gateway nodes learn from Redis about a
 * write — per ARCHITECTURE §4.3 the broadcast is "best effort, deliberately
 * not transactional"; catch-up (§5.3) is what repairs a dropped one, not
 * this bus.
 *
 * Never throws: the write it follows has already committed, so a Redis
 * hiccup must not turn into a 500 for a request that actually succeeded —
 * that would make every mutation fail whenever Redis is briefly unavailable,
 * exactly the kind of best-effort-in-name-only bug this section's own
 * comment warns against. Caught here once rather than at every call site.
 */
export async function publishRoomEvent(redis: Redis, payload: RoomEvent): Promise<void> {
  try {
    await redis.publish(MESSAGING_EVENTS_CHANNEL, JSON.stringify(payload));
  } catch (err) {
    // eslint-disable-next-line no-console
    console.warn(`[events-bus] broadcast failed (write already committed): ${String(err)}`);
  }
}
