/**
 * Web Push sender — system-communications-notifications (Task 8).
 *
 * POSTs an encrypted Web Push notification to the browser push endpoint.
 * Uses VAPID authorization (RFC 8292) and aes128gcm payload encryption (RFC 8030).
 * Returns the HTTP status; surfaces 410 Gone so the caller can prune the sub.
 */
import type { NotificationType } from '@zync/types'
import { assertSafePushEndpointUrl } from '@zync/utils'
import { buildVapidJwt, encryptWebPushPayload } from './vapid'

export interface PushSubscription {
  endpoint: string
  p256dh: string
  auth: string
}

export interface WebPushPayload {
  title: string
  body: string
  url: string
  tag: string
  type: NotificationType
}

export interface WebPushResult {
  endpoint: string
  status: number
  gone: boolean
}

/**
 * Send a Web Push notification to a single subscription.
 * Returns the HTTP status; callers should treat 410 as "prune this sub".
 */
export async function sendWebPush(
  sub: PushSubscription,
  payload: WebPushPayload,
  vapidPrivKeyB64: string,
  vapidPubKeyB64: string,
): Promise<WebPushResult> {
  assertSafePushEndpointUrl(sub.endpoint)

  const endpointUrl = new URL(sub.endpoint)
  const audience = `${endpointUrl.protocol}//${endpointUrl.host}`

  const jwt = await buildVapidJwt({
    audience,
    subject: 'mailto:noreply@zync.is',
    vapidPrivKeyB64,
    vapidPubKeyB64,
  })

  const payloadStr = JSON.stringify(payload)
  const encrypted = await encryptWebPushPayload({
    payload: payloadStr,
    clientP256dh: sub.p256dh,
    clientAuth: sub.auth,
  })

  const res = await fetch(sub.endpoint, {
    method: 'POST',
    headers: {
      Authorization: `vapid t=${jwt},k=${vapidPubKeyB64}`,
      'Content-Type': 'application/octet-stream',
      'Content-Encoding': 'aes128gcm',
      TTL: '86400',
    },
    body: encrypted,
  })

  return {
    endpoint: sub.endpoint,
    status: res.status,
    gone: res.status === 410,
  }
}
