/**
 * Notification delivery fanout — system-communications-notifications (Task 9).
 *
 * `deliverNotification` runs `Promise.allSettled` across all registered adapters
 * guarded by `canDeliver`. One adapter throwing does NOT prevent others.
 *
 * Adapters are constructed lazily per-invocation with the injected deps.
 * Adding WhatsApp/Slack = implement `NotificationAdapter`, add to ADAPTERS array.
 */
import type { DeliverableNotification, NotificationAdapter } from '@zync/types'
import type { Db } from '@zync/db/queries'
import type { Env } from '@zync/types'
import { EmailNotificationAdapter } from './adapters/email'
import { TelegramNotificationAdapter } from './adapters/telegram'
import { WebPushNotificationAdapter } from './adapters/web-push'
import { deliverPlatformNotification } from './platform'

function buildAdapters(db: Db, env: Env, tenantId: string): NotificationAdapter[] {
  return [
    new EmailNotificationAdapter(db, env, tenantId),
    new TelegramNotificationAdapter(db, env, tenantId),
    new WebPushNotificationAdapter(db, env, tenantId),
  ]
}

/**
 * Fan out a notification to all registered adapters.
 * Each adapter's `canDeliver` is checked before calling `deliver`.
 * Uses `Promise.allSettled` — one failure does not block others.
 */
export async function deliverNotification(
  userId: string,
  notification: DeliverableNotification,
  db: Db,
  env: Env,
  tenantId: string,
): Promise<void> {
  const adapters = buildAdapters(db, env, tenantId)

  await Promise.allSettled(
    adapters.map(async (adapter) => {
      try {
        const canDeliver = await adapter.canDeliver(userId, notification.type)
        if (!canDeliver) return
        await adapter.deliver(userId, notification)
      } catch {
        // Individual adapter errors are swallowed — allSettled handles isolation
      }
    }),
  )

  await deliverPlatformNotification(userId, notification, db, env, tenantId)
}
