"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleConnection = void 0;
const database_js_1 = require("../config/database.js");
const rateLimiter_js_1 = require("../middleware/rateLimiter.js");
const chatService_js_1 = require("../services/chatService.js");
const messageService_js_1 = require("../services/messageService.js");
const handleConnection = async (io, socket) => {
    console.log(`User connected: ${socket.user.username} (${socket.user.id})`);
    await updateUserOnlineStatus(socket.userId, true);
    const onlineUsers = await database_js_1.prisma.user.findMany({
        where: { isOnline: true },
        select: { id: true, username: true },
    });
    socket.emit("online_users", onlineUsers);
    await joinUserRooms(socket);
    socket.on("send_message", (data) => handleSendMessage(io, socket, data));
    socket.on("delete_message", (data) => handleDeleteMessage(io, socket, data));
    socket.on("react_to_message", (data) => handleReactToMessage(io, socket, data));
    socket.on("typing_start", (data) => handleTypingStart(io, socket, data));
    socket.on("typing_stop", (data) => handleTypingStop(io, socket, data));
    socket.on("join_room", (roomId) => handleJoinRoom(socket, roomId));
    socket.on("leave_room", (roomId) => handleLeaveRoom(socket, roomId));
    socket.on("messages_seen", (data) => handleMessagesSeen(io, socket, data));
    socket.on("disconnect", () => handleDisconnect(socket));
};
exports.handleConnection = handleConnection;
const handleTypingStart = async (io, socket, data) => {
    try {
        const isMember = await chatService_js_1.ChatService.checkRoomMembership(socket.userId, data.roomId);
        if (!isMember)
            return;
        io.to(data.roomId).emit("user_typing", {
            roomId: data.roomId,
            username: data.username,
        });
    }
    catch (error) {
        console.error(`Error handling typing start: ${error}`);
    }
};
const handleTypingStop = async (io, socket, data) => {
    try {
        const isMember = await chatService_js_1.ChatService.checkRoomMembership(socket.userId, data.roomId);
        if (!isMember)
            return;
        io.to(data.roomId).emit("user_stopped_typing", {
            roomId: data.roomId,
            username: data.username,
        });
    }
    catch (error) {
        console.error(`Error handling typing stop: ${error}`);
    }
};
const updateUserOnlineStatus = async (userId, isOnline) => {
    try {
        await database_js_1.prisma.user.update({
            where: { id: userId },
            data: {
                isOnline,
                lastSeen: new Date(),
            },
        });
    }
    catch (error) {
        console.error(`Error updating user online status: ${error}`);
    }
};
const joinUserRooms = async (socket) => {
    try {
        const userRooms = await database_js_1.prisma.chatRoomMember.findMany({
            where: { userId: socket.userId },
            include: { room: true },
        });
        userRooms.forEach(async (member) => {
            await socket.join(member.roomId);
            socket.to(member.roomId).emit("user_online", {
                userId: socket.userId,
                username: socket.user.username,
            });
        });
    }
    catch (error) {
        console.error(`Error joining user rooms: ${error}`);
    }
};
const handleSendMessage = async (io, socket, data) => {
    try {
        if (!data.roomId) {
            socket.emit("error", { message: "Room ID is required to send a message" });
            return;
        }
        if (data.image && data.image.length > 2 * 1024 * 1024) {
            socket.emit("error", { message: "Image size exceeds 2MB limit" });
            return;
        }
        if (!data.content && !data.image) {
            socket.emit("error", { message: "Message cannot be empty" });
            return;
        }
        if (!(0, rateLimiter_js_1.checkMessageRateLimit)(socket))
            return;
        const isMember = await chatService_js_1.ChatService.checkRoomMembership(socket.userId, data.roomId);
        if (!isMember) {
            socket.emit("error", { message: "Not authorized to send messages to this room" });
            return;
        }
        const result = await messageService_js_1.MessageService.sendMessage(socket.userId, data);
        if (result.success) {
            io.to(data.roomId).emit("new_message", result.data);
            io.to(data.roomId).emit("user_stopped_typing", {
                roomId: data.roomId,
                username: socket.user.username,
            });
        }
        else {
            socket.emit("error", { message: "Failed to send message" });
        }
    }
    catch (error) {
        console.error(`Error handling send message: ${error}`);
        socket.emit("error", { message: "Failed to send message" });
    }
};
const handleDeleteMessage = async (io, socket, data) => {
    try {
        const result = await messageService_js_1.MessageService.deleteMessage(socket.userId, data.messageId, data.roomId);
        if (result.success) {
            io.to(data.roomId).emit("message_deleted", {
                messageId: data.messageId,
                roomId: data.roomId,
            });
        }
        else {
            socket.emit("error", { message: result.error });
        }
    }
    catch (error) {
        console.error(`Error handling delete message: ${error}`);
        socket.emit("error", { message: "Failed to delete message" });
    }
};
const handleReactToMessage = async (io, socket, data) => {
    try {
        const result = await messageService_js_1.MessageService.reactToMessage(socket.userId, data);
        if (result.success) {
            const message = await database_js_1.prisma.message.findUnique({
                where: { id: data.messageId },
                select: { roomId: true },
            });
            if (message) {
                io.to(message.roomId).emit("message_reaction_updated", result.data);
            }
        }
        else {
            socket.emit("error", { message: result.error });
        }
    }
    catch (error) {
        console.error(`Error handling react to message: ${error}`);
        socket.emit("error", { message: "Failed to react to message" });
    }
};
const handleMessagesSeen = async (io, socket, data) => {
    try {
        const isMember = await chatService_js_1.ChatService.checkRoomMembership(socket.userId, data.roomId);
        if (!isMember) {
            socket.emit("error", { message: "Not authorized to access this room" });
            return;
        }
        const messagesInRoom = await database_js_1.prisma.message.findMany({
            where: {
                id: { in: data.messageIds },
                roomId: data.roomId,
            },
        });
        const validMessageIds = messagesInRoom.map((msg) => msg.id);
        if (validMessageIds.length === 0)
            return;
        const result = await messageService_js_1.MessageService.markMessagesAsSeen(socket.userId, validMessageIds);
        if (result.success && result.data) {
            for (const item of result.data) {
                io.to(data.roomId).emit("message_seen_update", {
                    messageId: item.messageId,
                    seenBy: item.seenBy,
                });
            }
        }
    }
    catch (error) {
        console.error(`Error handling messages seen: ${error}`);
        socket.emit("error", { message: "Failed to mark messages as seen" });
    }
};
const handleJoinRoom = async (socket, roomId) => {
    await socket.join(roomId);
};
const handleLeaveRoom = async (socket, roomId) => {
    await socket.leave(roomId);
};
const handleDisconnect = async (socket) => {
    console.log(`User disconnected: ${socket.user.username}`);
    await updateUserOnlineStatus(socket.userId, false);
    try {
        const userRooms = await database_js_1.prisma.chatRoomMember.findMany({
            where: {
                userId: socket.userId,
            },
        });
        userRooms.forEach((member) => {
            socket.to(member.roomId).emit("user_offline", {
                userId: socket.userId,
                username: socket.user.username,
            });
            socket.to(member.roomId).emit("user_stopped_typing", {
                roomId: member.roomId,
                username: socket.user.username,
            });
        });
    }
    catch (error) {
        console.error(`Error handling user disconnect: ${error}`);
    }
};
