/** * GET /api/chats/[chatId]/messages - Busca mensagens do chat * POST /api/chats/[chatId]/messages - Envia mensagem (fallback se Socket.io não estiver disponível) */ import { type NextRequest, NextResponse } from "next/server"; import { requireAuth } from "@/lib/auth/middleware"; import { connectMongoDB } from "@/lib/mongodb/connection"; import { Chat } from "@/lib/mongodb/models/Chat"; import { Message } from "@/lib/mongodb/models/Message"; import { secureLogger } from "@/lib/secure-logger"; import { getMessagesSchema, sendMessageSchema, } from "@/lib/validation/chat-schemas"; /** * GET /api/chats/[chatId]/messages * Busca mensagens do chat com paginação */ export async function GET( request: NextRequest, { params }: { params: Promise<{ chatId: string }> }, ) { try { const authResult = await requireAuth(request); if (authResult instanceof NextResponse) return authResult; const auth = authResult; const { chatId } = await params; const { searchParams } = new URL(request.url); const queryValidation = getMessagesSchema.safeParse({ page: searchParams.get("page"), limit: searchParams.get("limit"), }); if (!queryValidation.success) { return NextResponse.json( { success: false, error: "Parâmetros inválidos", details: queryValidation.error.issues, }, { status: 400 }, ); } const { page, limit } = queryValidation.data; await connectMongoDB(); // Verificar se chat existe e usuário tem acesso const chat = await Chat.findOne({ chat_id: chatId }); if (!chat) { return NextResponse.json( { success: false, error: "Chat não encontrado" }, { status: 404 }, ); } if (chat.buyer_id !== auth.userId && chat.seller_id !== auth.userId) { return NextResponse.json( { success: false, error: "Você não tem permissão para acessar este chat", }, { status: 403 }, ); } // Buscar mensagens (não deletadas) const skip = (page - 1) * limit; const messages = await Message.find({ chat_id: chatId, deleted_at: null, }) .sort({ created_at: -1 }) .skip(skip) .limit(limit); const total = await Message.countDocuments({ chat_id: chatId, deleted_at: null, }); // Marcar mensagens como lidas await Message.updateMany( { chat_id: chatId, sender_id: { $ne: auth.userId }, read_at: null, }, { $set: { read_at: new Date() }, }, ); // Atualizar contador de não lidas if (chat.buyer_id === auth.userId) { chat.buyer_unread_count = 0; } else { chat.seller_unread_count = 0; } await chat.save(); // Serializar mensagens (ordem reversa para mostrar mais antigas primeiro) const serializedMessages = messages.reverse().map((msg) => ({ _id: msg._id.toString(), chat_id: msg.chat_id, sender_id: msg.sender_id, content: msg.content, created_at: msg.created_at.toISOString(), read_at: msg.read_at?.toISOString() || null, edited_at: msg.edited_at?.toISOString() || null, message_type: msg.message_type, metadata: msg.metadata || null, })); return NextResponse.json( { success: true, messages: serializedMessages, pagination: { page, limit, total, totalPages: Math.ceil(total / limit), }, }, { status: 200 }, ); } catch (error) { secureLogger.error("❌ Erro ao buscar mensagens", { error: error instanceof Error ? error.message : "Erro desconhecido", stack: error instanceof Error ? error.stack : undefined, }); return NextResponse.json( { success: false, error: "Erro ao buscar mensagens" }, { status: 500 }, ); } } /** * POST /api/chats/[chatId]/messages * Envia mensagem (fallback se Socket.io não estiver disponível) */ export async function POST( request: NextRequest, { params }: { params: Promise<{ chatId: string }> }, ) { try { const authResult = await requireAuth(request); if (authResult instanceof NextResponse) return authResult; const auth = authResult; const { chatId } = await params; const body = await request.json(); const validationResult = sendMessageSchema.safeParse(body); if (!validationResult.success) { return NextResponse.json( { success: false, error: "Dados inválidos", details: validationResult.error.issues, }, { status: 400 }, ); } const { content } = validationResult.data; await connectMongoDB(); // Verificar se chat existe e usuário tem acesso const chat = await Chat.findOne({ chat_id: chatId }); if (!chat) { return NextResponse.json( { success: false, error: "Chat não encontrado" }, { status: 404 }, ); } if (chat.buyer_id !== auth.userId && chat.seller_id !== auth.userId) { return NextResponse.json( { success: false, error: "Você não tem permissão para enviar mensagens neste chat", }, { status: 403 }, ); } // Criar mensagem const message = new Message({ chat_id: chatId, sender_id: auth.userId, content, message_type: "text", }); await message.save(); // Atualizar chat chat.last_message_at = new Date(); chat.last_message_preview = content.substring(0, 100); if (chat.buyer_id === auth.userId) { chat.seller_unread_count += 1; } else { chat.buyer_unread_count += 1; } await chat.save(); // Tentar enviar via Socket.io se disponível try { const { getSocketIO } = await import("@/lib/socket/server"); const io = getSocketIO(); if (io) { io.to(`chat:${chatId}`).emit("new_message", { message: { _id: message._id.toString(), chat_id: message.chat_id, sender_id: message.sender_id, content: message.content, created_at: message.created_at.toISOString(), read_at: message.read_at?.toISOString() || null, message_type: message.message_type, }, }); } } catch (_socketError) { // Socket.io não disponível, mensagem já foi salva secureLogger.warn("Socket.io não disponível, mensagem salva via REST", { chatId, }); } return NextResponse.json( { success: true, message: { _id: message._id.toString(), chat_id: message.chat_id, sender_id: message.sender_id, content: message.content, created_at: message.created_at.toISOString(), read_at: message.read_at?.toISOString() || null, message_type: message.message_type, }, }, { status: 201 }, ); } catch (error) { secureLogger.error("❌ Erro ao enviar mensagem", { error: error instanceof Error ? error.message : "Erro desconhecido", stack: error instanceof Error ? error.stack : undefined, }); return NextResponse.json( { success: false, error: "Erro ao enviar mensagem" }, { status: 500 }, ); } }