import 'server-only'
import webpush from 'web-push'
import { db } from '@/lib/db'

// Web Push to a user's own devices.
//
// Runs alongside Telegram rather than instead of it: Telegram is one chat for
// one person, while this is per-account and stays on our own infrastructure —
// which is what a household member who should not be on Telegram will use.

let configured = false
function configure(): boolean {
  if (configured) return true
  const publicKey = process.env.VAPID_PUBLIC_KEY?.trim()
  const privateKey = process.env.VAPID_PRIVATE_KEY?.trim()
  if (!publicKey || !privateKey) return false
  webpush.setVapidDetails(
    process.env.VAPID_SUBJECT?.trim() || 'mailto:eric.n.tran@gmail.com',
    publicKey,
    privateKey,
  )
  configured = true
  return true
}

export interface PushPayload {
  title: string
  body: string
  /** Opened when the notification is tapped. */
  url?: string
  /** Collapses an earlier notification with the same tag instead of stacking. */
  tag?: string
}

/**
 * Push to every device registered to an account. Returns how many got through.
 *
 * Never throws: this reports on work that already succeeded, so a dead push
 * service must not fail the request that triggered it.
 *
 * A 404 or 410 means the endpoint is gone for good — the PWA was reinstalled,
 * site data was cleared, or the push service expired it. Those rows are deleted
 * rather than retried forever, which is the only way the table stays honest.
 */
export async function pushToUser(ownerId: string, payload: PushPayload): Promise<number> {
  if (!configure()) return 0
  const subs = await db.pushSubscription.findMany({ where: { ownerId } })
  if (subs.length === 0) return 0

  const body = JSON.stringify(payload)
  const dead: string[] = []
  let sent = 0

  await Promise.all(subs.map(async sub => {
    try {
      await webpush.sendNotification(
        { endpoint: sub.endpoint, keys: { p256dh: sub.p256dh, auth: sub.auth } },
        body,
        { TTL: 3600 },
      )
      sent++
    } catch (e) {
      const status = (e as { statusCode?: number })?.statusCode
      if (status === 404 || status === 410) dead.push(sub.id)
      else console.error('[push] send failed:', status, (e as Error)?.message)
    }
  }))

  if (dead.length) {
    await db.pushSubscription.deleteMany({ where: { id: { in: dead } } }).catch(() => {})
    console.warn(`[push] pruned ${dead.length} expired endpoint(s)`)
  }
  if (sent) {
    await db.pushSubscription
      .updateMany({ where: { ownerId }, data: { lastUsedAt: new Date() } })
      .catch(() => {})
  }
  return sent
}
