"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.assignDailyQuestionCallable = exports.assignDailyQuestion = void 0;
const functions = __importStar(require("firebase-functions"));
const admin = __importStar(require("firebase-admin"));
const CST_OFFSET_HOURS = -6;
/**
 * Scheduled function that assigns one daily question per couple every day.
 *
 * Schedule: 6:00 PM CST (America/Chicago) == 23:00 UTC.
 * Document path: couples/{coupleId}/daily_question/{date}
 *   - questionId: string
 *   - date: string (YYYY-MM-DD)
 *   - assignedAt: Timestamp
 *   - expiresAt: Timestamp (next day at 6 PM CST)
 *
 * Admin SDK bypasses Firestore rules; the `daily_question` doc is server-write
 * only (`allow write: if false` in rules).
 */
exports.assignDailyQuestion = functions.pubsub
    .schedule('0 23 * * *')
    .timeZone('America/Chicago')
    .onRun(async () => {
    const db = admin.firestore();
    const today = cstDateString();
    const nextDay = nextCstDateString();
    const questionId = await pickRandomQuestionId();
    if (!questionId) {
        console.error('[assignDailyQuestion] no active questions available');
        return;
    }
    const couplesSnap = await db.collection('couples').get();
    const assignedAt = admin.firestore.FieldValue.serverTimestamp();
    const expiresAt = timestampAt6PmCst(nextDay);
    const writes = couplesSnap.docs.map(async (coupleDoc) => {
        var _a;
        const coupleId = coupleDoc.id;
        const docRef = db
            .collection('couples')
            .doc(coupleId)
            .collection('daily_question')
            .doc(today);
        try {
            await docRef.create({
                questionId,
                date: today,
                assignedAt,
                expiresAt,
            });
        }
        catch (err) {
            if ((err === null || err === void 0 ? void 0 : err.code) === 6 || ((_a = err === null || err === void 0 ? void 0 : err.message) === null || _a === void 0 ? void 0 : _a.includes('ALREADY_EXISTS'))) {
                // Already assigned for today — idempotent.
                return;
            }
            console.error(`[assignDailyQuestion] failed for ${coupleId}:`, err);
        }
    });
    await Promise.all(writes);
    console.log(`[assignDailyQuestion] assigned ${questionId} to ${couplesSnap.size} couples for ${today}`);
});
/**
 * Callable function for immediate daily question assignment.
 *
 * Useful when a couple is newly created and should not wait for the next
 * scheduled run, or for manual admin/testing triggers.
 *
 * Body: { coupleId: string, date?: string }
 */
exports.assignDailyQuestionCallable = functions.https.onCall(async (data, context) => {
    var _a, _b, _c, _d;
    const callerId = (_a = context.auth) === null || _a === void 0 ? void 0 : _a.uid;
    if (!callerId) {
        throw new functions.https.HttpsError('unauthenticated', 'Caller must be authenticated.');
    }
    const coupleId = data === null || data === void 0 ? void 0 : data.coupleId;
    if (!coupleId || typeof coupleId !== 'string') {
        throw new functions.https.HttpsError('invalid-argument', 'coupleId is required.');
    }
    const db = admin.firestore();
    const coupleDoc = await db.collection('couples').doc(coupleId).get();
    if (!coupleDoc.exists) {
        throw new functions.https.HttpsError('not-found', 'Couple not found.');
    }
    // Caller must be a member of the couple.
    const userIds = ((_c = (_b = coupleDoc.data()) === null || _b === void 0 ? void 0 : _b.userIds) !== null && _c !== void 0 ? _c : []);
    if (!userIds.includes(callerId)) {
        throw new functions.https.HttpsError('permission-denied', 'Caller is not a couple member.');
    }
    const date = (data === null || data === void 0 ? void 0 : data.date) && typeof data.date === 'string' ? data.date : cstDateString();
    const questionId = await pickRandomQuestionId();
    if (!questionId) {
        throw new functions.https.HttpsError('internal', 'No active questions available.');
    }
    const nextDay = nextCstDateString(date);
    const docRef = db
        .collection('couples')
        .doc(coupleId)
        .collection('daily_question')
        .doc(date);
    try {
        await docRef.create({
            questionId,
            date,
            assignedAt: admin.firestore.FieldValue.serverTimestamp(),
            expiresAt: timestampAt6PmCst(nextDay),
        });
    }
    catch (err) {
        if ((err === null || err === void 0 ? void 0 : err.code) === 6 || ((_d = err === null || err === void 0 ? void 0 : err.message) === null || _d === void 0 ? void 0 : _d.includes('ALREADY_EXISTS'))) {
            throw new functions.https.HttpsError('already-exists', `Daily question already assigned for ${date}.`);
        }
        throw new functions.https.HttpsError('internal', 'Failed to assign daily question.');
    }
    return { success: true, coupleId, date, questionId };
});
/**
 * Picks a random active free question from the Firestore `questions` pool.
 *
 * The pool is expected to be a top-level collection with documents:
 *   - id: string
 *   - active: boolean
 *   - isPremium: boolean
 *
 * If no Firestore pool exists yet, falls back to a deterministic placeholder
 * so the app still functions during rollout. In production, keep the local
 * Room database and Firestore pool in sync through the existing seed flow.
 */
async function pickRandomQuestionId() {
    const db = admin.firestore();
    const snapshot = await db
        .collection('questions')
        .where('active', '==', true)
        .where('isPremium', '==', false)
        .get();
    if (snapshot.empty) {
        // Rollout fallback: keep the feature working until the questions pool is seeded.
        return 'q_default_daily';
    }
    const docs = snapshot.docs;
    const chosen = docs[Math.floor(Math.random() * docs.length)];
    return chosen.id;
}
/**
 * Returns today's date as YYYY-MM-DD in America/Chicago time.
 */
function cstDateString() {
    return formatCstDate(new Date());
}
/**
 * Returns tomorrow's date as YYYY-MM-DD relative to America/Chicago time.
 */
function nextCstDateString(from) {
    if (from) {
        const d = parseCstDate(from);
        d.setUTCDate(d.getUTCDate() + 1);
        return formatCstDate(d);
    }
    const d = new Date();
    const cst = applyCstOffset(d);
    cst.setUTCDate(cst.getUTCDate() + 1);
    return formatCstDate(cst);
}
function applyCstOffset(d) {
    const utcMs = d.getTime();
    const cstMs = utcMs + CST_OFFSET_HOURS * 60 * 60 * 1000;
    return new Date(cstMs);
}
function formatCstDate(d) {
    const cst = applyCstOffset(d);
    const y = cst.getUTCFullYear();
    const m = String(cst.getUTCMonth() + 1).padStart(2, '0');
    const day = String(cst.getUTCDate()).padStart(2, '0');
    return `${y}-${m}-${day}`;
}
function parseCstDate(dateStr) {
    const [y, m, day] = dateStr.split('-').map(Number);
    // Build a UTC timestamp that represents midnight CST, then reverse the offset.
    const cstMidnightMs = Date.UTC(y, m - 1, day, 0, 0, 0, 0);
    return new Date(cstMidnightMs - CST_OFFSET_HOURS * 60 * 60 * 1000);
}
function timestampAt6PmCst(dateStr) {
    const d = parseCstDate(dateStr);
    const utcMs = d.getTime();
    // 6:00 PM CST == 18:00 CST == 00:00 UTC next day.
    // We already have midnight CST in UTC form; add 18 hours.
    const at6pmCstMs = utcMs + 18 * 60 * 60 * 1000;
    return admin.firestore.Timestamp.fromMillis(at6pmCstMs);
}
//# sourceMappingURL=assignDailyQuestion.js.map