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 { getMainCharacter } from "@/lib/prisma/queries/characters"; import { getListingById } from "@/lib/prisma/queries/listings"; import { createNotification } from "@/lib/prisma/queries/notifications"; import { getPurchaseIntentionById, updatePurchaseIntentionStatus, } from "@/lib/prisma/queries/purchase-intentions"; import { getUserById } from "@/lib/prisma/queries/users"; import { secureLogger } from "@/lib/secure-logger"; /** * GET /api/listings/[id]/intentions/[intentionId] * Busca uma intenção específica */ export async function GET( request: NextRequest, { params }: { params: Promise<{ id: string; intentionId: string }> }, ) { try { const authResult = await requireAuth(request); if (authResult instanceof NextResponse) return authResult; const { intentionId: intentionIdParam } = await params; const intentionId = parseInt(intentionIdParam, 10); if (Number.isNaN(intentionId)) { return NextResponse.json( { success: false, error: "ID de intenção inválido" }, { status: 400 }, ); } const intention = await getPurchaseIntentionById(intentionId); if (!intention) { return NextResponse.json( { success: false, error: "Intenção não encontrada" }, { status: 404 }, ); } // Verificar permissões: vendedor ou comprador if ( intention.listing?.seller_id !== authResult.userId && intention.buyer_id !== authResult.userId ) { return NextResponse.json( { success: false, error: "Você não tem permissão para ver esta intenção", }, { status: 403 }, ); } return NextResponse.json( { success: true, intention, }, { status: 200 }, ); } catch (error) { secureLogger.error("❌ Erro ao buscar intenção", { error: error instanceof Error ? error.message : "Erro desconhecido", stack: error instanceof Error ? error.stack : undefined, }); return NextResponse.json( { success: false, error: "Erro ao buscar intenção" }, { status: 500 }, ); } } /** * PATCH /api/listings/[id]/intentions/[intentionId] * Atualiza o status de uma intenção (aceitar/rejeitar) */ export async function PATCH( request: NextRequest, { params }: { params: Promise<{ id: string; intentionId: string }> }, ) { try { const authResult = await requireAuth(request); if (authResult instanceof NextResponse) return authResult; const { intentionId: intentionIdParam } = await params; const intentionId = parseInt(intentionIdParam, 10); if (Number.isNaN(intentionId)) { return NextResponse.json( { success: false, error: "ID de intenção inválido" }, { status: 400 }, ); } const body = await request.json(); const { status, seller_response } = body; const sellerResponse = typeof seller_response === "string" && seller_response.trim().length > 0 ? seller_response : undefined; if (!status || !["accepted", "rejected"].includes(status)) { return NextResponse.json( { success: false, error: "Status inválido. Use 'accepted' ou 'rejected'", }, { status: 400 }, ); } // Buscar intenção const intention = await getPurchaseIntentionById(intentionId); if (!intention) { return NextResponse.json( { success: false, error: "Intenção não encontrada" }, { status: 404 }, ); } // Verificar se o usuário é o vendedor if (intention.listing?.seller_id !== authResult.userId) { return NextResponse.json( { success: false, error: "Apenas o vendedor pode aceitar ou rejeitar intenções", }, { status: 403 }, ); } // Verificar se a intenção ainda está pendente if (intention.status !== "pending") { return NextResponse.json( { success: false, error: `Esta intenção já foi ${intention.status}` }, { status: 400 }, ); } // Verificar se o anúncio ainda está disponível (ativo ou em escrow) const listing = await getListingById(intention.listing_id); if ( !listing || (listing.listing_status !== "active" && listing.listing_status !== "in_escrow") ) { return NextResponse.json( { success: false, error: "Anúncio não está mais disponível" }, { status: 400 }, ); } // Atualizar status da intenção (não altera status do listing) const updatedIntention = await updatePurchaseIntentionStatus( intentionId, status, sellerResponse, ); await sendSellerResponseToChat({ listing, intention, status, sellerResponse, sellerId: authResult.userId, }); // Criar notificação para o comprador await createNotification({ user_id: intention.buyer_id, notification_type: status === "accepted" ? "purchase" : "system", title: status === "accepted" ? "Intenção aceita!" : "Intenção rejeitada", message: status === "accepted" ? `O vendedor aceitou sua intenção de compra do item "${intention.listing?.item_name}"` : `O vendedor rejeitou sua intenção de compra do item "${intention.listing?.item_name}"`, related_id: intention.listing_id, send_whatsapp: false, }); secureLogger.info( `✅ Intenção ${status === "accepted" ? "aceita" : "rejeitada"}`, { userId: authResult.userId, intentionId, listingId: intention.listing_id, buyerId: intention.buyer_id, }, ); return NextResponse.json( { success: true, intention: updatedIntention, message: `Intenção ${status === "accepted" ? "aceita" : "rejeitada"} com sucesso`, }, { status: 200 }, ); } catch (error) { secureLogger.error("❌ Erro ao atualizar intenção", { error: error instanceof Error ? error.message : "Erro desconhecido", stack: error instanceof Error ? error.stack : undefined, }); return NextResponse.json( { success: false, error: "Erro ao atualizar intenção" }, { status: 500 }, ); } } async function sendSellerResponseToChat({ listing, intention, status, sellerResponse, sellerId, }: { listing: Awaited>; intention: Exclude< Awaited>, null >; status: "accepted" | "rejected"; sellerResponse?: string; sellerId: number; }) { try { if (!listing) return; const contentBase = sellerResponse?.trim() ? sellerResponse.trim() : status === "accepted" ? "O vendedor aceitou sua intenção de compra." : "O vendedor rejeitou sua intenção de compra."; const content = `[Intenções] ${contentBase}`; if (!content.trim()) return; const chatId = `${listing.listing_id}_${intention.buyer_id}_${listing.seller_id}`; await connectMongoDB(); let chat = await Chat.findOne({ chat_id: chatId }); if (!chat) { const [buyer, seller, buyerCharacter, sellerCharacter] = await Promise.all([ getUserById(intention.buyer_id), getUserById(listing.seller_id), getMainCharacter(intention.buyer_id), getMainCharacter(listing.seller_id), ]); chat = new Chat({ chat_id: chatId, listing_id: listing.listing_id, buyer_id: intention.buyer_id, seller_id: listing.seller_id, buyer_unread_count: 0, seller_unread_count: 0, is_active: listing.listing_status === "active", listing_cache: { item_name: listing.item_name, item_image_url: null, price_pix: listing.price_pix ?? null, price_tibia_coins: listing.price_tibia_coins ?? null, price_gold_coins: listing.price_gold_coins ?? null, server_name: listing.server_name, listing_status: listing.listing_status, }, buyer_cache: { user_id: buyer?.user_id ?? intention.buyer_id, username: buyer?.username ?? intention.buyer?.username ?? "Comprador", character_name: buyerCharacter?.character_name || null, }, seller_cache: { user_id: seller?.user_id ?? listing.seller_id, username: seller?.username ?? "Vendedor", character_name: sellerCharacter?.character_name || null, }, }); await chat.save(); } const message = new Message({ chat_id: chat.chat_id, sender_id: sellerId, content, message_type: "text", }); await message.save(); chat.last_message_at = new Date(); chat.last_message_preview = content.substring(0, 100); chat.buyer_unread_count = (chat.buyer_unread_count || 0) + 1; chat.is_active = listing.listing_status === "active"; await chat.save(); } catch (error) { secureLogger.error("❌ Falha ao enviar resposta para o chat", { error: error instanceof Error ? error.message : "Erro desconhecido", stack: error instanceof Error ? error.stack : undefined, }); } }