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

/**
 * Firestore trigger that notifies the other partner when a chat message is
 * sent in a conversation (the couple chat or a per-question discussion).
 *
 * Path: couples/{coupleId}/conversations/{conversationId}/messages/{messageId}
 *
 * Respects the recipient's `notifChatMessage` preference (default: enabled).
 */
export const onMessageWritten = functions.firestore
  .document('couples/{coupleId}/conversations/{conversationId}/messages/{messageId}')
  .onCreate(async (snap, context) => {
    const { coupleId, conversationId, messageId } = context.params as {
      coupleId: string
      conversationId: string
      messageId: string
    }

    const db = admin.firestore()
    const messageData = snap.data() as Partial<Record<string, unknown>>
    const authorId = typeof messageData.authorUserId === 'string' ? messageData.authorUserId : null
    if (!authorId) {
      console.warn(`[onMessageWritten] no authorUserId on message ${messageId}`)
      return
    }

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

    const userIds = (coupleDoc.data()?.userIds ?? []) as string[]
    const partnerId = userIds.find((uid) => uid !== authorId)
    if (!partnerId) {
      console.warn(`[onMessageWritten] no partner found for couple ${coupleId}`)
      return
    }

    const partnerUserDoc = await db.collection('users').doc(partnerId).get()

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

    const tokens: string[] = []
    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(`[onMessageWritten] no FCM tokens for partner ${partnerId}`)
      return
    }

    // The recipient sees the message from the author (their partner), so surface the author's
    // photo/name — the in-app chat bubble uses sender_avatar_url to show the partner's face.
    const authorDoc = await db.collection('users').doc(authorId).get()
    const authorPhotoUrl = (authorDoc.data()?.photoUrl as string | undefined) ?? ''
    const authorName = (authorDoc.data()?.displayName as string | undefined) ?? ''

    const payload: admin.messaging.MessagingPayload = {
      notification: {
        title: authorName ? `${authorName} sent a message` : 'Your partner sent a message',
        body: 'Tap to read and reply.',
      },
      data: {
        type: 'chat_message',
        couple_id: coupleId,
        conversation_id: conversationId,
        ...(authorPhotoUrl ? { sender_avatar_url: authorPhotoUrl } : {}),
      },
    }

    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(`[onMessageWritten] some notifications failed:`, failures)
    }

    console.log(
      `[onMessageWritten] notified partner ${partnerId} for conversation ${conversationId} in couple ${coupleId}`
    )
  })
