"use strict";
// oms/src/services/messageRecordService.ts
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageRecordService = void 0;
const messageRecordModel_1 = require("../models/messageRecordModel");
class MessageRecordService {
    /**
     * Creates a new message push record.
     * @param recordData Message record data.
     * @returns The newly created message record object.
     */
    async createMessageRecord(recordData) {
        const newRecord = new messageRecordModel_1.MessageRecord(recordData);
        return await newRecord.save();
    }
    /**
     * Gets paginated message records with filtering and sorting support.
     * @param page Page number.
     * @param limit Number of records per page.
     * @param filters Filter conditions.
     * @param sortField Field to sort by.
     * @param sortOrder Sort order ('asc' or 'desc').
     * @returns An object containing records and the total count.
     */
    async getPaginatedRecords(page = 1, limit = 10, filters = {}, sortField = "createdAt", sortOrder = "desc") {
        // Build the query conditions
        const query = {};
        if (filters.uid) {
            query.uid = filters.uid;
        }
        if (filters.activityName) {
            query.activityName = filters.activityName;
        }
        if (filters.templateName) {
            query.templateName = filters.templateName;
        }
        if (filters.status !== undefined) {
            query.status = filters.status;
        }
        const sort = {};
        sort[sortField] = sortOrder === "asc" ? 1 : -1;
        const skip = (page - 1) * limit;
        const records = await messageRecordModel_1.MessageRecord.find(query).sort(sort).skip(skip).limit(limit);
        const total = await messageRecordModel_1.MessageRecord.countDocuments(query);
        return { records, total };
    }
    /**
     * Gets all message records for a specific user UID.
     * @param uid User UID.
     * @returns A list of message records.
     */
    async getRecordsByUid(uid) {
        return await messageRecordModel_1.MessageRecord.find({ uid }).sort({ createdAt: -1 });
    }
    /**
     * Gets all message records related to a specific activity ID.
     * @param activityId Message activity ID.
     * @returns A list of message records.
     */
    async getRecordsByActivityId(activityId) {
        return await messageRecordModel_1.MessageRecord.find({ activityId }).sort({ createdAt: -1 });
    }
    /**
     * Gets a single message record by ID.
     * @param recordId Message record ID.
     * @returns The message record object or null.
     */
    async getSingleRecord(recordId) {
        return await messageRecordModel_1.MessageRecord.findById(recordId);
    }
    /**
     * Updates the status of a message record.
     * @param recordId Message record ID.
     * @param updateData Data to update.
     * @returns The updated message record object.
     */
    async updateMessageRecord(recordId, updateData) {
        return await messageRecordModel_1.MessageRecord.findByIdAndUpdate(recordId, updateData, { new: true });
    }
    /**
     * Gets overall message push statistics.
     */
    async getOverallStatistics() {
        try {
            const result = await messageRecordModel_1.MessageRecord.aggregate([
                // 1. Group messages by status
                {
                    $group: {
                        _id: "$status",
                        count: { $sum: 1 },
                    },
                },
                // 2. Transform the result into a more manageable format
                {
                    $group: {
                        _id: null,
                        total_records: { $sum: "$count" },
                        status_counts: {
                            $push: {
                                k: { $toString: "$_id" },
                                v: "$count",
                            },
                        },
                    },
                },
                // 3. Reformat the output and calculate all rates
                {
                    $project: {
                        _id: 0,
                        totalRecords: "$total_records",
                        sent: {
                            $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "1"] }] }, 0],
                        },
                        delivered: {
                            $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "2"] }] }, 0],
                        },
                        opened: {
                            $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "3"] }] }, 0],
                        },
                        failed: {
                            $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "-1"] }] }, 0],
                        },
                        // Sent success rate = (sent + delivered + opened) / total
                        sentSuccessRate: {
                            $cond: [
                                { $eq: ["$total_records", 0] },
                                0,
                                {
                                    $divide: [
                                        {
                                            $sum: [
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "1"] }] }, 0] },
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "2"] }] }, 0] },
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "3"] }] }, 0] },
                                            ],
                                        },
                                        "$total_records",
                                    ],
                                },
                            ],
                        },
                        // Delivered rate = delivered / (sent + delivered)
                        deliveredRate: {
                            $cond: [
                                {
                                    $eq: [
                                        {
                                            $sum: [
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "1"] }] }, 0] },
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "2"] }] }, 0] },
                                            ],
                                        },
                                        0,
                                    ],
                                },
                                0,
                                {
                                    $divide: [
                                        { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "2"] }] }, 0] },
                                        {
                                            $sum: [
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "1"] }] }, 0] },
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "2"] }] }, 0] },
                                            ],
                                        },
                                    ],
                                },
                            ],
                        },
                        // Opened rate = opened / (delivered + opened)
                        openedRate: {
                            $cond: [
                                {
                                    $eq: [
                                        {
                                            $sum: [
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "2"] }] }, 0] },
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "3"] }] }, 0] },
                                            ],
                                        },
                                        0,
                                    ],
                                },
                                0,
                                {
                                    $divide: [
                                        { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "3"] }] }, 0] },
                                        {
                                            $sum: [
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "2"] }] }, 0] },
                                                { $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "3"] }] }, 0] },
                                            ],
                                        },
                                    ],
                                },
                            ],
                        },
                        // Token invalidation rate
                        tokenInvalidationRate: {
                            $cond: [{ $eq: ["$total_records", 0] }, 0, { $divide: [{ $ifNull: [{ $arrayElemAt: ["$status_counts.v", { $indexOfArray: ["$status_counts.k", "-1"] }] }, 0] }, "$total_records"] }],
                        },
                    },
                },
            ]);
            return result[0];
        }
        catch (error) {
            console.error("Error fetching overall statistics:", error);
            return null;
        }
    }
    /**
     * Gets message statistics grouped by activity.
     */
    async getStatisticsByActivity() {
        try {
            const results = await messageRecordModel_1.MessageRecord.aggregate([
                // 1. Group by both activityId and status
                {
                    $group: {
                        _id: { activityId: "$activityId", activityName: "$activityName", status: "$status" },
                        count: { $sum: 1 },
                    },
                },
                // 2. Regroup by activityId to summarize counts and get the activityName
                {
                    $group: {
                        _id: "$_id.activityId", // Group by the ID
                        activityName: { $first: "$_id.activityName" }, // Keep the name
                        total_sent: { $sum: "$count" },
                        sent_count: { $sum: { $cond: [{ $eq: ["$_id.status", 1] }, "$count", 0] } },
                        delivered_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", 2] }, "$count", 0] },
                        },
                        opened_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", 3] }, "$count", 0] },
                        },
                        failed_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", -1] }, "$count", 0] },
                        },
                    },
                },
                // 3. Calculate rates and format the output
                {
                    $project: {
                        _id: 0,
                        activityId: "$_id",
                        activityName: "$activityName",
                        totalSent: "$total_sent",
                        sent: "$sent_count",
                        delivered: "$delivered_count",
                        opened: "$opened_count",
                        failed: "$failed_count",
                        sentSuccessRate: {
                            $cond: [{ $eq: ["$total_sent", 0] }, 0, { $divide: [{ $sum: ["$sent_count", "$delivered_count", "$opened_count"] }, "$total_sent"] }],
                        },
                        tokenInvalidationRate: {
                            $cond: [{ $eq: ["$total_sent", 0] }, 0, { $divide: ["$failed_count", "$total_sent"] }],
                        },
                        deliveredRate: {
                            $cond: [{ $eq: [{ $sum: ["$sent_count", "$delivered_count"] }, 0] }, 0, { $divide: ["$delivered_count", { $sum: ["$sent_count", "$delivered_count"] }] }],
                        },
                        openedRate: {
                            $cond: [{ $eq: [{ $sum: ["$delivered_count", "$opened_count"] }, 0] }, 0, { $divide: ["$opened_count", { $sum: ["$delivered_count", "$opened_count"] }] }],
                        },
                    },
                },
                // 4. Sort by deliveredRate in descending order
                {
                    $sort: { deliveredRate: -1 },
                },
            ]);
            return results;
        }
        catch (error) {
            console.error("Error fetching statistics by activity:", error);
            return [];
        }
    }
    /**
     * Gets message statistics grouped by strategy.
     */
    async getStatisticsByStrategy() {
        try {
            const results = await messageRecordModel_1.MessageRecord.aggregate([
                // 1. Group by both strategyId and status
                {
                    $group: {
                        _id: { strategyId: "$strategyId", strategyName: "$strategyName", status: "$status" },
                        count: { $sum: 1 },
                    },
                },
                // 2. Regroup by strategyId to summarize counts and get the strategyName
                {
                    $group: {
                        _id: "$_id.strategyId",
                        strategyName: { $first: "$_id.strategyName" },
                        total_sent: { $sum: "$count" },
                        sent_count: { $sum: { $cond: [{ $eq: ["$_id.status", 1] }, "$count", 0] } },
                        delivered_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", 2] }, "$count", 0] },
                        },
                        opened_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", 3] }, "$count", 0] },
                        },
                        failed_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", -1] }, "$count", 0] },
                        },
                    },
                },
                // 3. Calculate rates and format the output
                {
                    $project: {
                        _id: 0,
                        strategyId: "$_id",
                        strategyName: "$strategyName",
                        totalSent: "$total_sent",
                        sent: "$sent_count",
                        delivered: "$delivered_count",
                        opened: "$opened_count",
                        failed: "$failed_count",
                        sentSuccessRate: {
                            $cond: [{ $eq: ["$total_sent", 0] }, 0, { $divide: [{ $sum: ["$sent_count", "$delivered_count", "$opened_count"] }, "$total_sent"] }],
                        },
                        tokenInvalidationRate: {
                            $cond: [{ $eq: ["$total_sent", 0] }, 0, { $divide: ["$failed_count", "$total_sent"] }],
                        },
                        deliveredRate: {
                            $cond: [{ $eq: [{ $sum: ["$sent_count", "$delivered_count"] }, 0] }, 0, { $divide: ["$delivered_count", { $sum: ["$sent_count", "$delivered_count"] }] }],
                        },
                        openedRate: {
                            $cond: [{ $eq: [{ $sum: ["$delivered_count", "$opened_count"] }, 0] }, 0, { $divide: ["$opened_count", { $sum: ["$delivered_count", "$opened_count"] }] }],
                        },
                    },
                },
                // 4. Sort by deliveredRate in descending order
                {
                    $sort: { deliveredRate: -1 },
                },
            ]);
            return results;
        }
        catch (error) {
            console.error("Error fetching statistics by strategy:", error);
            return [];
        }
    }
    /**
     * Gets message statistics grouped by template.
     */
    async getStatisticsByTemplate() {
        try {
            const results = await messageRecordModel_1.MessageRecord.aggregate([
                // 1. Group by both templateId and status
                {
                    $group: {
                        _id: { templateId: "$templateId", templateName: "$templateName", status: "$status" },
                        count: { $sum: 1 },
                    },
                },
                // 2. Regroup by templateId to summarize counts and get the templateName
                {
                    $group: {
                        _id: "$_id.templateId",
                        templateName: { $first: "$_id.templateName" },
                        total_sent: { $sum: "$count" },
                        sent_count: { $sum: { $cond: [{ $eq: ["$_id.status", 1] }, "$count", 0] } },
                        delivered_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", 2] }, "$count", 0] },
                        },
                        opened_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", 3] }, "$count", 0] },
                        },
                        failed_count: {
                            $sum: { $cond: [{ $eq: ["$_id.status", -1] }, "$count", 0] },
                        },
                    },
                },
                // 3. Calculate rates and format the output
                {
                    $project: {
                        _id: 0,
                        templateId: "$_id",
                        templateName: "$templateName",
                        totalSent: "$total_sent",
                        sent: "$sent_count",
                        delivered: "$delivered_count",
                        opened: "$opened_count",
                        failed: "$failed_count",
                        sentSuccessRate: {
                            $cond: [{ $eq: ["$total_sent", 0] }, 0, { $divide: [{ $sum: ["$sent_count", "$delivered_count", "$opened_count"] }, "$total_sent"] }],
                        },
                        tokenInvalidationRate: {
                            $cond: [{ $eq: ["$total_sent", 0] }, 0, { $divide: ["$failed_count", "$total_sent"] }],
                        },
                        deliveredRate: {
                            $cond: [{ $eq: [{ $sum: ["$sent_count", "$delivered_count"] }, 0] }, 0, { $divide: ["$delivered_count", { $sum: ["$sent_count", "$delivered_count"] }] }],
                        },
                        openedRate: {
                            $cond: [{ $eq: [{ $sum: ["$delivered_count", "$opened_count"] }, 0] }, 0, { $divide: ["$opened_count", { $sum: ["$delivered_count", "$opened_count"] }] }],
                        },
                    },
                },
                // 4. Sort by deliveredRate in descending order
                {
                    $sort: { deliveredRate: -1 },
                },
            ]);
            return results;
        }
        catch (error) {
            console.error("Error fetching statistics by template:", error);
            return [];
        }
    }
    /**
     * Gets daily message sending trends.
     */
    async getDailySentTrends() {
        try {
            const results = await messageRecordModel_1.MessageRecord.aggregate([
                // 1. Truncate actualSendAt to the day, ignoring time
                {
                    $project: {
                        _id: 0,
                        date: {
                            $dateTrunc: { date: "$actualSendAt", unit: "day", timezone: "America/Los_Angeles" },
                        },
                        status: "$status",
                    },
                },
                // 2. Group by date and status
                {
                    $group: {
                        _id: { date: "$date", status: "$status" },
                        count: { $sum: 1 },
                    },
                },
                // 3. Regroup to summarize counts by date
                {
                    $group: {
                        _id: "$_id.date",
                        totalSent: { $sum: "$count" },
                        sent: { $sum: { $cond: [{ $eq: ["$_id.status", 1] }, "$count", 0] } },
                        delivered: { $sum: { $cond: [{ $eq: ["$_id.status", 2] }, "$count", 0] } },
                        opened: { $sum: { $cond: [{ $eq: ["$_id.status", 3] }, "$count", 0] } },
                        failed: { $sum: { $cond: [{ $eq: ["$_id.status", -1] }, "$count", 0] } },
                    },
                },
                // 4. Calculate rates and format the output
                {
                    $project: {
                        _id: 0,
                        date: "$_id",
                        totalSent: "$totalSent",
                        sent: "$sent",
                        delivered: "$delivered",
                        opened: "$opened",
                        failed: "$failed",
                        // Sent success rate = (sent + delivered + opened) / total
                        sentSuccessRate: {
                            $cond: [{ $eq: ["$totalSent", 0] }, 0, { $divide: [{ $sum: ["$sent", "$delivered", "$opened"] }, "$totalSent"] }],
                        },
                        // Delivered rate = delivered / (sent + delivered)
                        deliveredRate: {
                            $cond: [{ $eq: [{ $sum: ["$sent", "$delivered"] }, 0] }, 0, { $divide: ["$delivered", { $sum: ["$sent", "$delivered"] }] }],
                        },
                        // Opened rate = opened / (delivered + opened)
                        openedRate: {
                            $cond: [{ $eq: [{ $sum: ["$delivered", "$opened"] }, 0] }, 0, { $divide: ["$opened", { $sum: ["$delivered", "$opened"] }] }],
                        },
                        // Token invalidation rate
                        tokenInvalidationRate: {
                            $cond: [{ $eq: ["$totalSent", 0] }, 0, { $divide: ["$failed", "$totalSent"] }],
                        },
                    },
                },
                // 5. Sort by date in ascending order
                {
                    $sort: { date: 1 },
                },
            ]);
            return results;
        }
        catch (error) {
            console.error("Error fetching daily sent trends:", error);
            return [];
        }
    }
    /**
     * Calculates the average delivery time.
     */
    async getAverageDeliveryTime() {
        try {
            const result = await messageRecordModel_1.MessageRecord.aggregate([
                // 1. Filter for delivered messages (status 2 or 3) with existing timestamps
                {
                    $match: {
                        status: { $in: [2, 3] },
                        actualSendAt: { $exists: true, $ne: null },
                        deliveredAt: { $exists: true, $ne: null },
                    },
                },
                // 2. Calculate the time difference (in milliseconds) from send to delivery
                {
                    $addFields: {
                        time_to_deliver: {
                            $subtract: ["$deliveredAt", "$actualSendAt"],
                        },
                    },
                },
                // 3. Calculate the average time
                {
                    $group: {
                        _id: null,
                        avg_time_to_deliver_ms: { $avg: "$time_to_deliver" },
                    },
                },
                // 4. Convert to seconds for readability
                {
                    $project: {
                        _id: 0,
                        averageTimeToDeliverInSeconds: {
                            $divide: ["$avg_time_to_deliver_ms", 1000],
                        },
                    },
                },
            ]);
            return result[0];
        }
        catch (error) {
            console.error("Error calculating average delivery time:", error);
            return null;
        }
    }
}
exports.MessageRecordService = MessageRecordService;
