"use strict";
// oms/src/controller/userController.ts
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const userService_1 = __importDefault(require("../services/userService")); // 导入用户服务
const fcmService_1 = require("../services/fcmService");
const messageRecordModel_1 = require("../models/messageRecordModel");
const utils_1 = require("../libs/utils");
// Define an array of valid IUser keys for runtime checking
// This ensures that only properties defined in IUser are considered for MongoDB queries
const USER_MODEL_KEYS = [
    "uid",
    "project",
    "network",
    "campaign",
    "adgroup",
    "creative",
    "prod",
    "libraryName",
    "cc",
    "lang",
    "manufacturer",
    "deviceModel",
    "deviceInfo",
    "hardware",
    "deviceMem",
    "apiLevel",
    "versionName",
    "versionCode",
    "fmToken",
    "tags",
    "firstLoginAt",
    "lastActiveAt",
];
/**
 * 检查错误是否为 FCM 令牌失效错误。
 * @param error 错误对象
 * @returns 如果是令牌失效错误则返回 true
 */
function isTokenInvalidationError(error) {
    return error && (error.code === "messaging/registration-token-not-registered" || error.code === "messaging/invalid-registration-token");
}
class UserController {
    /**
     * 处理创建新用户的请求。
     * POST /api/users
     */
    async createUser(req, res) {
        try {
            const { uid, ...otherData } = req.body; // uid 现在是必需的 // 检查 uid 是否存在
            if (!uid) {
                res.status(400).json({ message: "用户 UID 是必需的。" });
                return;
            } // 如果 uid 存在，则直接用 req.body 来创建用户
            const user = await userService_1.default.createUser(req.body);
            res.status(201).json(user);
        }
        catch (error) {
            // 检查是否是重复键错误 (uid 唯一性冲突)
            if (error.message.includes("E11000 duplicate key error") || error.message.includes("duplicate key")) {
                res.status(409).json({
                    message: "用户 UID 已存在，请使用其他 UID。",
                    error: error.message,
                });
            }
            else {
                res.status(500).json({ message: "创建用户时出错", error: error.message });
            }
        }
    }
    /**
     * 处理通过 UID 获取用户的请求。
     * GET /api/users/:uid
     */
    async getUserByUid(req, res) {
        try {
            const { uid } = req.params;
            const user = await userService_1.default.getUserByUid(uid);
            if (user) {
                res.status(200).json(user);
            }
            else {
                res.status(404).json({ message: `未找到 UID 为 ${uid} 的用户。` });
            }
        }
        catch (error) {
            res.status(500).json({ message: "获取用户时出错", error: error.message });
        }
    }
    /**
     * 处理更新用户的请求。
     * PUT /api/users/:uid
     */
    async updateUser(req, res) {
        try {
            const { uid } = req.params;
            const updateData = req.body; // 业务逻辑检查：不允许直接通过 PUT 请求更新 UID
            if (updateData.uid && updateData.uid !== uid) {
                res.status(400).json({ message: "不允许修改用户 UID。" });
                return;
            }
            delete updateData.uid; // 确保不会尝试更新 UID
            const updatedUser = await userService_1.default.updateUser(uid, updateData);
            if (updatedUser) {
                res.status(200).json(updatedUser);
            }
            else {
                res.status(404).json({ message: `未找到 UID 为 ${uid} 的用户。` });
            }
        }
        catch (error) {
            res.status(500).json({ message: "更新用户时出错", error: error.message });
        }
    }
    /**
     * 处理删除用户的请求。
     * DELETE /api/users/:uid
     */
    async deleteUser(req, res) {
        try {
            const { uid } = req.params;
            const deleted = await userService_1.default.deleteUser(uid);
            if (deleted) {
                res.status(204).send(); // 204 No Content，表示成功删除但无返回内容
            }
            else {
                res.status(404).json({ message: `未找到 UID 为 ${uid} 的用户。` });
            }
        }
        catch (error) {
            res.status(500).json({ message: "删除用户时出错", error: error.message });
        }
    }
    /**
     * 处理获取所有用户或按分页和查询参数获取用户列表的请求。
     * GET /api/users?page=1&limit=10&project=1&cc=US
     */
    async getPaginatedUsers(req, res) {
        try {
            const page = parseInt(req.query.page) || 1;
            const limit = parseInt(req.query.limit) || 30;
            // 从 req.query 中筛选出只与 IUser 相关的属性，作为 MongoDB 的查询条件
            const mongooseQuery = {};
            for (const key in req.query) {
                if (Object.prototype.hasOwnProperty.call(req.query, key)) {
                    // 检查 key 是否在 USER_MODEL_KEYS 中 (即是否是 IUser 的有效属性)
                    // 并且不是分页参数 'page' 或 'limit'
                    if (USER_MODEL_KEYS.includes(key)) {
                        const queryValue = req.query[key];
                        // --- 新增：处理日期范围查询 ---
                        if (key === "firstLoginAt" || key === "lastActiveAt") {
                            // 检查是否为日期范围格式 (e.g., "2023-01-01,2023-01-31")
                            const dates = queryValue.split(",");
                            if (dates.length === 2) {
                                const startDate = new Date(dates[0]);
                                const endDate = new Date(dates[1]);
                                // 确保日期有效
                                if (!isNaN(startDate.getTime()) && !isNaN(endDate.getTime())) {
                                    mongooseQuery[key] = {
                                        $gte: startDate,
                                        $lte: endDate,
                                    };
                                    continue; // 继续下一个查询参数
                                }
                                else {
                                    console.warn(`[API] Invalid date range format for ${key}: ${queryValue}. Skipping.`);
                                }
                            }
                        }
                        // --- 其他属性处理，保持不变 ---
                        if (key === "project" || key === "apiLevel" || key === "versionCode") {
                            const numValue = parseInt(queryValue);
                            if (!isNaN(numValue)) {
                                mongooseQuery[key] = numValue;
                            }
                        }
                        else if (key === "deviceMem") {
                            const numValue = parseFloat(queryValue);
                            if (!isNaN(numValue)) {
                                mongooseQuery[key] = numValue;
                            }
                        }
                        else if (key === "tags") {
                            // 如果 tags 是以逗号分隔的字符串，可以将其转换为数组
                            mongooseQuery[key] = queryValue.split(",").map((s) => s.trim());
                        }
                        else {
                            // 对于其他字符串类型，直接赋值
                            mongooseQuery[key] = queryValue;
                        }
                    }
                }
            }
            // 为了确保类型兼容性，我们暂时使用any来处理mongooseQuery
            const { users, total } = await userService_1.default.getPaginatedUsers(page, limit, mongooseQuery // 传入处理后的查询对象
            );
            res.status(200).json({
                page,
                limit,
                total,
                users,
            });
        }
        catch (error) {
            res.status(500).json({ message: "获取用户列表时出错", error: error.message });
        }
    }
    /**
     * 点对点发送消息给指定 UID 的用户。
     * POST /api/users/send-message
     */
    async sendDirectMessage(req, res) {
        const { uid, title, content, image, bigger, action, param, extend } = req.body;
        // 1. 验证必需参数
        if (!uid || !title || !content) {
            res.status(400).json({ message: "UID, title, and content are required." });
            return;
        }
        try {
            // 2. 找到用户并获取 FCM Token
            const user = await userService_1.default.getUserByUid(uid);
            if (!user || !user.fmToken) {
                // 用户不存在或没有FCM Token，直接创建失败记录并返回
                await messageRecordModel_1.MessageRecord.create({
                    uid,
                    title,
                    content,
                    image,
                    bigger,
                    action,
                    param,
                    extend,
                    plannedSendAt: new Date(),
                    actualSendAt: new Date(),
                    status: -1,
                    errno: "User not found or no FCM token",
                });
                res.status(404).json({ message: `User with UID ${uid} not found or no FCM token.` });
                return;
            }
            // 3. 先创建 MessageRecord 记录
            const messageRecord = new messageRecordModel_1.MessageRecord({
                uid,
                cc: user.cc,
                title,
                content,
                image,
                bigger,
                action: action || "go/app", // 默认 action
                param,
                extend,
                plannedSendAt: new Date(),
                status: 0, // 初始状态为 0（未发送）
            });
            await messageRecord.save();
            // 4. 获取记录的 _id 作为消息 ID
            const fcmService = fcmService_1.FCMService.getInstance();
            const messageData = (0, utils_1.filterEmptyProps)({
                msgid: messageRecord._id.toString(), // 使用数据库记录的 _id 作为消息 ID
                title,
                content,
                image: image || "",
                bigger: bigger?.toString() || "false",
                action: action || "go/app",
                param: param || "",
                extend: extend || "",
            });
            // 5. 调用 FCMService 发送消息
            let fcmResult;
            try {
                fcmResult = await fcmService.sendMessage(user.fmToken, messageData);
            }
            catch (fcmError) {
                fcmResult = fcmError;
            }
            let messageStatus = 1;
            let errorMessage = null;
            let fcmReceipt = null;
            if (fcmResult instanceof Error) {
                messageStatus = -1;
                errorMessage = fcmResult.message;
                console.warn(`[FCM] 发送消息至 UID ${uid} 失败: ${fcmResult.message}`);
                // --- IMPORTANT: 如果错误是令牌失效，则清空该用户的 fmToken ---
                if (isTokenInvalidationError(fcmResult)) {
                    console.warn(`[FCM] 检测到无效令牌，自动清除 UID ${uid} 的 fmToken。`);
                    await userService_1.default.updateUser(uid, { fmToken: null });
                    errorMessage += " (Token cleared)";
                }
            }
            else {
                fcmReceipt = fcmResult;
                console.log(`[FCM] 发送消息至 UID ${uid} 成功！`);
            }
            // 6. 更新 MessageRecord 记录
            await messageRecordModel_1.MessageRecord.findByIdAndUpdate(messageRecord._id, {
                status: messageStatus,
                actualSendAt: new Date(),
                errno: errorMessage,
                fcmReceipt,
            });
            if (messageStatus === 1) {
                res.status(200).json({ message: "Message sent successfully.", fcmReceipt });
            }
            else {
                res.status(500).json({ message: "Failed to send message.", error: errorMessage });
            }
        }
        catch (error) {
            // 7. 捕获并处理所有其他异常
            console.error(`[API] 发送消息至 UID ${uid} 时发生意外错误:`, error);
            res.status(500).json({ message: "An unexpected error occurred while sending the message.", error: error.message });
        }
    }
    /**
     * Handles bulk messaging to an array of UIDs.
     * POST /api/users/send-bulk-message
     */
    async sendBulkMessage(req, res) {
        const { uids, title, content, image, bigger, action, param, extend } = req.body;
        // 1. Validate required parameters.
        if (!uids || !Array.isArray(uids) || uids.length === 0 || !title || !content) {
            res.status(400).json({ message: "An array of uids, title, and content are required." });
            return;
        }
        const results = [];
        // 2. Use Promise.all to handle concurrent message sending.
        const promises = uids.map(async (uid) => {
            try {
                const user = await userService_1.default.getUserByUid(uid);
                if (!user || !user.fmToken) {
                    // User not found or no FCM Token. Create a failure record.
                    const failedRecord = await messageRecordModel_1.MessageRecord.create({
                        uid,
                        title,
                        content,
                        image,
                        bigger,
                        action,
                        param,
                        extend,
                        plannedSendAt: new Date(),
                        actualSendAt: new Date(),
                        status: -1,
                        errno: "User not found or no FCM token",
                    });
                    results.push({ uid, status: "failed", error: "User not found or no FCM token", recordId: failedRecord._id });
                    return;
                }
                // Create a MessageRecord document before sending.
                const messageRecord = new messageRecordModel_1.MessageRecord({
                    uid,
                    cc: user.cc,
                    title,
                    content,
                    image,
                    bigger,
                    action: action || "go/app",
                    param,
                    extend,
                    plannedSendAt: new Date(),
                    status: 0,
                });
                await messageRecord.save();
                const fcmService = fcmService_1.FCMService.getInstance();
                const messageData = (0, utils_1.filterEmptyProps)({
                    msgid: messageRecord._id.toString(),
                    title,
                    content,
                    image: image || "",
                    bigger: bigger?.toString() || "false",
                    action: action || "go/app",
                    param: param || "",
                    extend: extend || "",
                });
                // Send message.
                let fcmResult;
                try {
                    fcmResult = await fcmService.sendMessage(user.fmToken, messageData);
                }
                catch (fcmError) {
                    fcmResult = fcmError;
                }
                let messageStatus = 1;
                let errorMessage = null;
                let fcmReceipt = null;
                if (fcmResult instanceof Error) {
                    messageStatus = -1;
                    errorMessage = fcmResult.message;
                    // --- IMPORTANT: 如果错误是令牌失效，则清空该用户的 fmToken ---
                    if (isTokenInvalidationError(fcmResult)) {
                        await userService_1.default.updateUser(uid, { fmToken: null });
                        errorMessage += " (Token cleared)";
                    }
                }
                else {
                    fcmReceipt = fcmResult;
                }
                // Update the MessageRecord with the send result.
                await messageRecordModel_1.MessageRecord.findByIdAndUpdate(messageRecord._id, {
                    status: messageStatus,
                    actualSendAt: new Date(),
                    errno: errorMessage,
                    fcmReceipt,
                });
                if (messageStatus === 1) {
                    results.push({ uid, status: "success", fcmReceipt, recordId: messageRecord._id });
                }
                else {
                    results.push({ uid, status: "failed", error: errorMessage, recordId: messageRecord._id });
                }
            }
            catch (error) {
                console.error(`[API] Error processing bulk message for UID ${uid}:`, error);
                results.push({ uid, status: "failed", error: error.message });
            }
        });
        await Promise.all(promises);
        res.status(200).json({
            message: "Bulk message sending complete. See details for each recipient.",
            totalRecipients: uids.length,
            results,
        });
    }
}
const userController = new UserController();
exports.default = userController;
