import type { Channel, DeliveryResult, Notification } from './types';
import { discordChannel } from './discord';
import { apnsChannel } from './apns';
import { fcmChannel } from './fcm';

// Fan a notification out to every configured channel.
//
// Channels are independent and none of them may break a producer: a job that finished has finished
// whether or not a banner appeared. So every channel is awaited with its own error boundary, and the
// dispatcher always resolves.

const channels: Channel[] = [apnsChannel, fcmChannel, discordChannel];

/** Registered here rather than imported at the top so channels can be added without touching producers. */
export function registerChannel(channel: Channel): void {
  channels.push(channel);
}

export function configuredChannels(): string[] {
  return channels.filter((c) => c.isConfigured()).map((c) => c.name);
}

export async function dispatch(n: Notification): Promise<DeliveryResult[]> {
  const active = channels.filter((c) => c.isConfigured());
  if (active.length === 0) return [];

  return Promise.all(
    active.map(async (c) => {
      try {
        return await c.send(n);
      } catch (err) {
        // A channel that throws instead of returning is a bug in that channel, not a reason to fail
        // the notification or the producer behind it.
        console.error(`[notify] channel ${c.name} threw:`, err instanceof Error ? err.message : err);
        return { channel: c.name, sent: 0, failed: 1 };
      }
    }),
  );
}
