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

/**
 * Fires the "It's a match!" notification when a date match is created.
 *
 * Trigger: couples/{coupleId}/date_matches/{dateIdeaId} (onCreate)
 *
 * Date swipes are E2E-encrypted, so the server can no longer detect mutual love.
 * Mutual-match detection now happens client-side (whichever partner records the
 * second LOVE writes the match marker, validated by Firestore rules). This trigger
 * only sends the push to both partners — it never reads swipe content.
 *
 * Idempotency: `fcmNotified` is claimed in a transaction so concurrent invocations
 * (or a client retry) never double-send. The match doc id is the date idea id, so
 * the marker itself is already de-duplicated by the client transaction + rules.
 */
export const notifyOnDateMatch = functions.firestore
  .document('couples/{coupleId}/date_matches/{dateIdeaId}')
  .onCreate(async (snap, context) => {
    if (!snap.exists) return

    const { coupleId, dateIdeaId } = context.params as {
      coupleId: string
      dateIdeaId: string
    }

    const db = admin.firestore()
    const matchRef = snap.ref

    // Atomically claim the FCM send so concurrent invocations don't double-send.
    const shouldSend = await db.runTransaction(async (tx) => {
      const doc = await tx.get(matchRef)
      if (!doc.exists || doc.data()?.fcmNotified === true) return false
      tx.update(matchRef, { fcmNotified: true })
      return true
    })

    if (!shouldSend) return

    const coupleDoc = await db.collection('couples').doc(coupleId).get()
    const userIds = (coupleDoc.data()?.userIds ?? []) as string[]
    await Promise.all(userIds.map((uid) => notifyDateMatch(db, uid, coupleId, dateIdeaId)))
  })

async function notifyDateMatch(
  db: admin.firestore.Firestore,
  userId: string,
  coupleId: string,
  dateIdeaId: string
): Promise<void> {
  await db.collection('users').doc(userId).collection('notification_queue').add({
    type: 'date_match',
    title: "It's a match!",
    body: "You both want to go on this date. Time to make it happen.",
    read: false,
    createdAt: admin.firestore.FieldValue.serverTimestamp(),
  })

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

  await Promise.allSettled(
    tokens.map((token) =>
      admin.messaging().send({
        token,
        notification: {
          title: "It's a match!",
          body: "You both want to go on this date. Time to make it happen.",
        },
        data: {
          type: 'date_match',
          couple_id: coupleId,
          date_idea_id: dateIdeaId,
        },
      })
    )
  )
}

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
}
