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

/**
 * Proactive daily question reminder.
 *
 * Schedule: 4:00 PM America/Chicago (2 hours before the question expires at 6 PM).
 *
 * Logic:
 *  1. Query all `daily_question` docs (collection group) with expiresAt in the
 *     next 3 hours — these are the ones expiring today.
 *  2. For each, count the answers subcollection. If 0 answers (neither partner
 *     has responded), the couple needs a nudge.
 *  3. Skip couples where a gentle_reminder or automated_daily_reminder was
 *     already sent today (avoid over-notifying couples where a partner already
 *     manually nudged the other).
 *  4. Send FCM to all users in the couple + write to notification_queue.
 *  5. Record automated_daily_reminder/{docId} so this function is idempotent
 *     on re-runs.
 */
export const sendDailyQuestionProactiveReminder = functions.pubsub
  .schedule('0 16 * * *')
  .timeZone('America/Chicago')
  .onRun(async () => {
    const db = admin.firestore()
    const messaging = admin.messaging()
    const now = Date.now()
    const threeHoursMs = 3 * 60 * 60 * 1000

    // Docs expiring within the next 3 hours — the active window for today's question.
    const expiringSnap = await db
      .collectionGroup('daily_question')
      .where('expiresAt', '>', admin.firestore.Timestamp.fromMillis(now))
      .where('expiresAt', '<', admin.firestore.Timestamp.fromMillis(now + threeHoursMs))
      .get()

    let notified = 0
    let skipped = 0

    await Promise.all(
      expiringSnap.docs.map(async (questionDoc) => {
        const coupleRef = questionDoc.ref.parent.parent
        if (!coupleRef) return

        const reminderId = `auto_${questionDoc.id}`
        const reminderRef = coupleRef.collection('daily_reminders').doc(reminderId)

        // Idempotency: skip if we already sent this reminder.
        const alreadySent = await reminderRef.get()
        if (alreadySent.exists) { skipped++; return }

        // Skip if a manual gentle_reminder was sent today (same date key).
        const dateKey = questionDoc.id // daily_question docs are keyed by date (YYYY-MM-DD)
        const gentleRef = coupleRef.collection('gentle_reminders').doc(dateKey)
        const gentleSent = await gentleRef.get()
        if (gentleSent.exists) { skipped++; return }

        // Check answer count — only remind if nobody has answered yet.
        const answersSnap = await questionDoc.ref.collection('answers').limit(1).get()
        if (!answersSnap.empty) { skipped++; return }

        // Fetch couple members.
        const coupleDoc = await coupleRef.get()
        const userIds = (coupleDoc.data()?.userIds ?? []) as string[]
        if (userIds.length === 0) { skipped++; return }

        // Claim the reminder slot atomically.
        try {
          await db.runTransaction(async (tx) => {
            const fresh = await tx.get(reminderRef)
            if (fresh.exists) throw new Error('already_sent')
            tx.set(reminderRef, {
              sentAt: admin.firestore.FieldValue.serverTimestamp(),
              questionDate: dateKey,
            })
          })
        } catch {
          skipped++
          return
        }

        // Send FCM + notification_queue entry to every user in the couple.
        await Promise.all(
          userIds.map((userId) =>
            sendReminder(db, messaging, userId, coupleRef.id, dateKey)
          )
        )
        notified += userIds.length
      })
    )

    console.log(
      `[sendDailyQuestionProactiveReminder] scanned ${expiringSnap.size} docs; notified ${notified} users; skipped ${skipped}`
    )
  })

async function sendReminder(
  db: admin.firestore.Firestore,
  messaging: admin.messaging.Messaging,
  userId: string,
  coupleId: string,
  questionDate: string
): Promise<void> {
  // In-app notification record.
  await db
    .collection('users')
    .doc(userId)
    .collection('notification_queue')
    .add({
      type: 'daily_question_reminder',
      title: "Tonight's question is waiting.",
      body: 'Answer together before it expires.',
      read: false,
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
    })

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

  const sendResults = await Promise.allSettled(
    tokens.map((token) =>
      messaging.send({
        token,
        notification: {
          title: "Tonight's question is waiting.",
          body: 'Answer together before it expires.',
        },
        data: {
          type: 'daily_question_reminder',
          couple_id: coupleId,
          question_date: questionDate,
        },
      })
    )
  )

  sendResults.forEach((result, i) => {
    if (result.status === 'rejected') {
      console.warn(
        `[sendDailyQuestionProactiveReminder] FCM failed for token ${tokens[i]}:`,
        result.reason
      )
    }
  })
}

async function getUserTokens(
  db: admin.firestore.Firestore,
  userId: string
): Promise<string[]> {
  const tokens: string[] = []
  const userDoc = await db.collection('users').doc(userId).get()
  const legacyToken = userDoc.data()?.fcmToken
  if (typeof legacyToken === 'string' && legacyToken.length > 0) {
    tokens.push(legacyToken)
  }
  const tokenSnap = await db
    .collection('users')
    .doc(userId)
    .collection('fcmTokens')
    .get()
  tokenSnap.docs.forEach((doc) => {
    const t = doc.data()?.token
    if (typeof t === 'string' && t.length > 0 && !tokens.includes(t)) {
      tokens.push(t)
    }
  })
  return tokens
}
