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

/**
 * Firestore trigger that sends an FCM notification to the other partner when
 * one partner writes an answer under
 * couples/{coupleId}/daily_question/{date}/answers/{userId}.
 *
 * The notification payload is a data message so the client can route directly to
 * the answer reveal screen. It also contains a `notification` block for
 * system-tray display when the app is in the background.
 */
export const onAnswerWritten = functions.firestore
  .document('couples/{coupleId}/daily_question/{date}/answers/{userId}')
  .onCreate(async (snap, context) => {
    const { coupleId, date, userId } = context.params as {
      coupleId: string
      date: string
      userId: string
    }

    const db = admin.firestore()

    const coupleDoc = await db.collection('couples').doc(coupleId).get()
    if (!coupleDoc.exists) {
      console.warn(`[onAnswerWritten] couple ${coupleId} not found`)
      return
    }

    const userIds = (coupleDoc.data()?.userIds ?? []) as string[]

    // Security review Batch 2: re-verify the writer actually belongs to this couple
    // before sending a cross-user notification. Firestore rules already enforce this,
    // but defense-in-depth ensures a stray/forged answer doc can't trigger a partner ping.
    if (!userIds.includes(userId)) {
      console.warn(`[onAnswerWritten] writer ${userId} is not a member of couple ${coupleId}`)
      return
    }

    const partnerId = userIds.find((uid) => uid !== userId)
    if (!partnerId) {
      console.warn(`[onAnswerWritten] no partner found for couple ${coupleId}`)
      return
    }

    // Look up the partner's FCM tokens. We support a legacy `fcmToken` field
    // on the user doc and a dedicated `fcmTokens` subcollection for multiple devices.
    const tokens: string[] = []
    const partnerUserDoc = await db.collection('users').doc(partnerId).get()
    if (partnerUserDoc.exists) {
      const legacyToken = partnerUserDoc.data()?.fcmToken
      if (typeof legacyToken === 'string' && legacyToken.length > 0) {
        tokens.push(legacyToken)
      }
    }

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

    if (tokens.length === 0) {
      console.log(`[onAnswerWritten] no FCM tokens for partner ${partnerId}`)
      return
    }

    // Respect the partner's notification preference (opt-out; default is enabled).
    const notifEnabled = partnerUserDoc.data()?.notifPartnerAnswered
    if (notifEnabled === false) {
      console.log(`[onAnswerWritten] partner ${partnerId} has partner-answered notifications off`)
      return
    }

    const answerData = snap.data() as Partial<Record<string, unknown>>
    const questionId = typeof answerData.questionId === 'string' ? answerData.questionId : ''

    // Sender (the partner who just answered) avatar — used as the notification large icon.
    const senderDoc = await db.collection('users').doc(userId).get()
    const senderAvatar = senderDoc.data()?.photoUrl

    const payload: admin.messaging.MessagingPayload = {
      notification: {
        title: 'Your partner just answered!',
        body: "See what they shared for tonight's prompt.",
      },
      data: {
        type: 'partner_answered',
        couple_id: coupleId,
        question_id: questionId,
        date,
        ...(typeof senderAvatar === 'string' && senderAvatar.length > 0
          ? { sender_avatar_url: senderAvatar }
          : {}),
      },
    }

    const sendResults = await Promise.allSettled(
      tokens.map((token) =>
        admin.messaging().send({ ...payload, token } as admin.messaging.Message)
      )
    )

    const failures: string[] = []
    sendResults.forEach((result, index) => {
      if (result.status === 'rejected') {
        failures.push(`${tokens[index]}: ${String(result.reason)}`)
      }
    })

    if (failures.length > 0) {
      console.error(`[onAnswerWritten] some notifications failed:`, failures)
    }

    // Track last activity time on the couple doc for re-engagement targeting.
    await db.collection('couples').doc(coupleId).update({
      lastAnsweredAt: admin.firestore.FieldValue.serverTimestamp(),
    }).catch((e) => console.warn('[onAnswerWritten] lastAnsweredAt update failed:', e))

    console.log(
      `[onAnswerWritten] notified partner ${partnerId} for couple ${coupleId} question ${questionId}`
    )
  })
