import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'

const THREE_DAYS_MS = 3 * 24 * 60 * 60 * 1000
const TEN_DAYS_MS = 10 * 24 * 60 * 60 * 1000
const REENGAGEMENT_COOLDOWN_MS = 3 * 24 * 60 * 60 * 1000

/**
 * Re-engagement nudge for couples who went quiet.
 *
 * Schedule: 12:00 PM America/Chicago daily.
 *
 * Targets couples whose lastAnsweredAt is between 3 and 10 days ago —
 * recently lapsed but not completely inactive. Respects a 3-day cooldown
 * via reengagementSentAt to avoid spamming.
 *
 * Requires a Firestore composite index on couples: lastAnsweredAt ASC.
 */
export const sendReengagementReminder = functions.pubsub
  .schedule('0 12 * * *')
  .timeZone('America/Chicago')
  .onRun(async () => {
    const db = admin.firestore()
    const messaging = admin.messaging()
    const now = Date.now()
    const threeDaysAgo = admin.firestore.Timestamp.fromMillis(now - THREE_DAYS_MS)
    const tenDaysAgo = admin.firestore.Timestamp.fromMillis(now - TEN_DAYS_MS)

    const snap = await db
      .collection('couples')
      .where('lastAnsweredAt', '>', tenDaysAgo)
      .where('lastAnsweredAt', '<', threeDaysAgo)
      .limit(200)
      .get()

    let notified = 0
    let skipped = 0

    await Promise.all(
      snap.docs.map(async (coupleDoc) => {
        const data = coupleDoc.data()
        const coupleId = coupleDoc.id
        const userIds = (data.userIds ?? []) as string[]
        if (userIds.length === 0) { skipped++; return }

        // Respect cooldown — don't re-send within 3 days.
        const sentAt = data.reengagementSentAt as admin.firestore.Timestamp | undefined
        if (sentAt && now - sentAt.toMillis() < REENGAGEMENT_COOLDOWN_MS) {
          skipped++
          return
        }

        // Claim atomically so parallel runs don't double-send.
        const claimed = await db.runTransaction(async (tx) => {
          const fresh = await tx.get(coupleDoc.ref)
          const freshSentAt = fresh.data()?.reengagementSentAt as admin.firestore.Timestamp | undefined
          if (freshSentAt && now - freshSentAt.toMillis() < REENGAGEMENT_COOLDOWN_MS) return false
          tx.update(coupleDoc.ref, {
            reengagementSentAt: admin.firestore.FieldValue.serverTimestamp(),
          })
          return true
        })

        if (!claimed) { skipped++; return }

        await Promise.all(userIds.map((uid) => sendNudge(db, messaging, uid, coupleId)))
        notified += userIds.length
      })
    )

    console.log(`[sendReengagementReminder] scanned ${snap.size}; notified ${notified}; skipped ${skipped}`)
  })

async function sendNudge(
  db: admin.firestore.Firestore,
  messaging: admin.messaging.Messaging,
  userId: string,
  coupleId: string
): Promise<void> {
  await db.collection('users').doc(userId).collection('notification_queue').add({
    type: 'reengagement',
    title: "It's been a while.",
    body: "Tonight's question is a good reason to reconnect.",
    read: false,
    createdAt: admin.firestore.FieldValue.serverTimestamp(),
  })

  const tokens = await getUserTokens(db, userId)
  if (tokens.length === 0) return

  await Promise.allSettled(
    tokens.map((token) =>
      messaging.send({
        token,
        notification: {
          title: "It's been a while.",
          body: "Tonight's question is a good reason to reconnect.",
        },
        data: {
          type: 'reengagement',
          couple_id: coupleId,
        },
      })
    )
  )
}

async function getUserTokens(
  db: admin.firestore.Firestore,
  userId: string
): Promise<string[]> {
  const tokens: string[] = []
  const userDoc = await db.collection('users').doc(userId).get()
  const legacy = userDoc.data()?.fcmToken
  if (typeof legacy === 'string' && legacy.length > 0) tokens.push(legacy)

  const snap = await db.collection('users').doc(userId).collection('fcmTokens').get()
  snap.docs.forEach((doc) => {
    const t = doc.data()?.token
    if (typeof t === 'string' && t.length > 0 && !tokens.includes(t)) tokens.push(t)
  })
  return tokens
}
