import UserMiddleware from "../Middleware/UserAuthorization";
import UserPushService from "../Services/UserPushService";
import UserNotificationRuleService from "../Services/UserNotificationRuleService";
import PushNotificationService from "../Services/PushNotificationService";
import PushNotificationUtil from "../Utils/PushNotificationUtil";
import logger, { getLogAttributesFromRequest } from "../Utils/Logger";
import Response from "../Utils/Response";
import BaseAPI from "./BaseAPI";
import BadDataException from "../../Types/Exception/BadDataException";
import NotAuthenticatedException from "../../Types/Exception/NotAuthenticatedException";
import ObjectID from "../../Types/ObjectID";
import PushDeviceType from "../../Types/PushNotification/PushDeviceType";
import UserPush from "../../Models/DatabaseModels/UserPush";
function getAuthenticatedUserId(req) {
    var _a;
    const userId = (_a = req
        .userAuthorization) === null || _a === void 0 ? void 0 : _a.userId;
    if (!userId) {
        throw new NotAuthenticatedException("You must be logged in to perform this action.");
    }
    return userId;
}
export default class UserPushAPI extends BaseAPI {
    constructor() {
        super(UserPush, UserPushService);
        this.router.post(`/user-push/register`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                req = req;
                const userId = getAuthenticatedUserId(req);
                if (!req.body.deviceToken) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device token is required"));
                }
                const validDeviceTypes = Object.values(PushDeviceType);
                if (!req.body.deviceType ||
                    !validDeviceTypes.includes(req.body.deviceType)) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device type must be one of: " + validDeviceTypes.join(", ")));
                }
                if (!req.body.projectId) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Project ID is required"));
                }
                // Check if device is already registered
                const existingDevice = await this.service.findOneBy({
                    query: {
                        userId: userId,
                        projectId: new ObjectID(req.body.projectId),
                        deviceToken: req.body.deviceToken,
                    },
                    props: {
                        isRoot: true,
                    },
                    select: {
                        _id: true,
                    },
                });
                if (existingDevice) {
                    return Response.sendErrorResponse(req, res, new BadDataException("This device is already registered for push notifications"));
                }
                // Create new device registration
                const userPush = new UserPush();
                userPush.userId = userId;
                userPush.projectId = new ObjectID(req.body.projectId);
                userPush.deviceToken = req.body.deviceToken;
                userPush.deviceType = req.body.deviceType;
                userPush.deviceName = req.body.deviceName || "Unknown Device";
                userPush.isVerified = true; // Web, iOS, and Android devices are verified immediately
                const savedDevice = await this.service.create({
                    data: userPush,
                    props: {
                        isRoot: true,
                    },
                });
                // Create default notification rules for this registered push device
                try {
                    await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod({
                        projectId: new ObjectID(req.body.projectId),
                        userId,
                        notificationMethod: {
                            userPushId: savedDevice.id,
                        },
                    });
                }
                catch (e) {
                    logger.error(e, getLogAttributesFromRequest(req));
                }
                return Response.sendJsonObjectResponse(req, res, {
                    success: true,
                    deviceId: savedDevice._id.toString(),
                });
            }
            catch (error) {
                next(error);
            }
        });
        this.router.post(`/user-push/unregister`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            try {
                req = req;
                const userId = getAuthenticatedUserId(req);
                if (!req.body.deviceToken) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device token is required"));
                }
                await this.service.deleteBy({
                    query: {
                        userId: userId,
                        deviceToken: req.body.deviceToken,
                    },
                    limit: 100,
                    skip: 0,
                    props: {
                        isRoot: true,
                    },
                });
                return Response.sendJsonObjectResponse(req, res, {
                    success: true,
                    message: "Device unregistered successfully",
                });
            }
            catch (error) {
                return next(error);
            }
        });
        this.router.post(`/user-push/:deviceId/test-notification`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            var _a;
            try {
                req = req;
                const userId = getAuthenticatedUserId(req);
                if (!req.params["deviceId"]) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device ID is required"));
                }
                // Get the device
                const device = await this.service.findOneById({
                    id: new ObjectID(req.params["deviceId"]),
                    props: {
                        isRoot: true,
                    },
                    select: {
                        userId: true,
                        deviceName: true,
                        deviceToken: true,
                        deviceType: true,
                        isVerified: true,
                        projectId: true,
                    },
                });
                if (!device) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device not found"));
                }
                // Check if the device belongs to the current user
                if (((_a = device.userId) === null || _a === void 0 ? void 0 : _a.toString()) !== userId.toString()) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Unauthorized access to device"));
                }
                if (!device.isVerified) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device is not verified"));
                }
                try {
                    // Send test notification
                    const testMessage = PushNotificationUtil.createGenericNotification({
                        title: "Test Notification from OneUptime",
                        body: "This is a test notification to verify your device is working correctly.",
                        clickAction: "/dashboard",
                        tag: "test-notification",
                        requireInteraction: false,
                    });
                    await PushNotificationService.sendPushNotification({
                        devices: [
                            Object.assign({ token: device.deviceToken }, (device.deviceName && {
                                name: device.deviceName,
                            })),
                        ],
                        message: testMessage,
                        deviceType: device.deviceType,
                    }, {
                        isSensitive: false,
                        projectId: device.projectId,
                        userId: device.userId,
                    });
                }
                catch (error) {
                    throw new BadDataException(`Failed to send test notification: ${error.message}`);
                }
                return Response.sendJsonObjectResponse(req, res, {
                    success: true,
                    message: "Test notification sent successfully",
                });
            }
            catch (error) {
                return next(error);
            }
        });
        this.router.post(`/user-push/:deviceId/verify`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            var _a;
            try {
                req = req;
                const userId = getAuthenticatedUserId(req);
                if (!req.params["deviceId"]) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device ID is required"));
                }
                const device = await this.service.findOneById({
                    id: new ObjectID(req.params["deviceId"]),
                    props: {
                        isRoot: true,
                    },
                    select: {
                        userId: true,
                        projectId: true,
                    },
                });
                if (!device) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device not found"));
                }
                // Check if the device belongs to the current user
                if (((_a = device.userId) === null || _a === void 0 ? void 0 : _a.toString()) !== userId.toString()) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Unauthorized access to device"));
                }
                await this.service.verifyDevice(device._id.toString());
                // Create default notification rules for this verified push device
                try {
                    await UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod({
                        projectId: new ObjectID(device.projectId.toString()),
                        userId,
                        notificationMethod: {
                            userPushId: device.id,
                        },
                    });
                }
                catch (e) {
                    logger.error(e, getLogAttributesFromRequest(req));
                }
                return Response.sendEmptySuccessResponse(req, res);
            }
            catch (error) {
                return next(error);
            }
        });
        this.router.post(`/user-push/:deviceId/unverify`, UserMiddleware.getUserMiddleware, async (req, res, next) => {
            var _a;
            try {
                req = req;
                const userId = getAuthenticatedUserId(req);
                if (!req.params["deviceId"]) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device ID is required"));
                }
                const device = await this.service.findOneById({
                    id: new ObjectID(req.params["deviceId"]),
                    props: {
                        isRoot: true,
                    },
                    select: {
                        userId: true,
                    },
                });
                if (!device) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Device not found"));
                }
                // Check if the device belongs to the current user
                if (((_a = device.userId) === null || _a === void 0 ? void 0 : _a.toString()) !== userId.toString()) {
                    return Response.sendErrorResponse(req, res, new BadDataException("Unauthorized access to device"));
                }
                await this.service.unverifyDevice(device._id.toString());
                return Response.sendEmptySuccessResponse(req, res);
            }
            catch (error) {
                return next(error);
            }
        });
    }
}
//# sourceMappingURL=UserPushAPI.js.map