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

/**
 * Firestore trigger that notifies partners when a game session is created or completed.
 * 
 * Path: couples/{coupleId}/sessions/{sessionId}
 * Condition: onWrite (create, update, delete)
 */
export const onGameSessionUpdate = functions.firestore
  .document('couples/{coupleId}/sessions/{sessionId}')
  .onWrite(async (change, context) => {
    const { coupleId, sessionId } = context.params as { coupleId: string; sessionId: string }

    const db = admin.firestore()
    const messaging = admin.messaging()

    // Get the session document
    const sessionDoc = await db.collection('couples').doc(coupleId).collection('sessions').doc(sessionId).get()
    const session = sessionDoc.data()
    if (!session) {
      console.log(`[onGameSessionUpdate] session ${sessionId} not found, skipping`)
      return
    }

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

    const coupleData = coupleDoc.data() ?? {}
    const userIds = (coupleData.userIds ?? []) as string[]
    if (userIds.length !== 2) {
      console.warn(`[onGameSessionUpdate] invalid couple ${coupleId}: expected 2 users, got ${userIds.length}`)
      return
    }

    const partnerA = userIds[0]
    const partnerB = userIds[1]

    // Get user display names for notifications
    const userA = await db.collection('users').doc(partnerA).get()
    const userB = await db.collection('users').doc(partnerB).get()
    const partnerAName = userA.data()?.displayName ?? 'Partner A'
    const partnerBName = userB.data()?.displayName ?? 'Partner B'
    const avatarA = userA.data()?.photoUrl as string | undefined
    const avatarB = userB.data()?.photoUrl as string | undefined

    // Check if session was just created (status = "active")
    const previousData = change.before.data() ?? {}
    const currentData = change.after.data() ?? {}

    const wasInactive = (previousData.status ?? '') !== 'active'
    const isActiveNow = currentData.status === 'active'

    if (wasInactive && isActiveNow) {
      // New session started — notify the OTHER partner, naming the person who started it.
      const startedBy = currentData.startedByUserId
      const gameType = currentData.gameType ?? 'wheel'
      const recipientId = startedBy === partnerA ? partnerB : partnerA
      const starterName = startedBy === partnerA ? partnerAName : partnerBName
      const starterAvatar = startedBy === partnerA ? avatarA : avatarB
      await notifyPartner(
        db, messaging, recipientId, starterName, gameType,
        'partner_started_game', `${starterName} has started a game. Tap to join!`, coupleId,
        starterAvatar
      )
      return
    }

    // Check if session was completed
    const wasActive = (previousData.status ?? '') === 'active'
    const isCompletedNow = currentData.status === 'completed'

    if (wasActive && isCompletedNow) {
      // The session is complete (both partners have answered) — the reveal is ready for each of
      // them, so notify BOTH, each naming the OTHER partner.
      const gt = currentData.gameType ?? 'wheel'
      await notifyPartner(
        db, messaging, partnerA, partnerBName, gt,
        'partner_finished_game', `${partnerBName} finished — tap to see your results!`, coupleId,
        avatarB
      )
      await notifyPartner(
        db, messaging, partnerB, partnerAName, gt,
        'partner_finished_game', `${partnerAName} finished — tap to see your results!`, coupleId,
        avatarA
      )
      return
    }
  })

/**
 * Send notification to partner via FCM and write to notification_queue.
 */
async function notifyPartner(
  db: admin.firestore.Firestore,
  messaging: admin.messaging.Messaging,
  partnerId: string,
  partnerName: string,
  gameType: string,
  notificationType: string,
  body: string,
  coupleId: string,
  senderAvatarUrl?: string
): Promise<void> {
  const title =
    notificationType === 'partner_finished_game'
      ? `${partnerName} finished the game`
      : `${partnerName} is playing`
  const notificationPayload = {
    type: notificationType,
    title,
    body: body,
  }

  // Write an in-app notification record for the partner
  await db
    .collection('users')
    .doc(partnerId)
    .collection('notification_queue')
    .add({
      ...notificationPayload,
      read: false,
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
    })

  // Collect the partner's FCM tokens
  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(`[notifyPartner] no FCM tokens for ${partnerId}`)
    return
  }

  const fcmMessage: admin.messaging.Message = {
    token: tokens[0],
    notification: {
      title: notificationPayload.title,
      body: notificationPayload.body,
    },
    data: {
      type: notificationPayload.type,
      couple_id: coupleId,
      game_type: gameType,
      ...(senderAvatarUrl && senderAvatarUrl.length > 0
        ? { sender_avatar_url: senderAvatarUrl }
        : {}),
    },
  }

  const sendResults = await Promise.allSettled(
    tokens.map((token) => messaging.send({ ...fcmMessage, token }))
  )

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

  if (failures.length > 0) {
    console.error(`[notifyPartner] some notifications failed:`, failures)
  } else {
    console.log(`[notifyPartner] notified ${partnerId} (${notificationType})`)
  }
}
