import { type NextRequest, NextResponse } from "next/server"; import { requireAuth } from "@/lib/auth/middleware"; import { placeBid } from "@/lib/prisma/queries/listings"; import { createNotification } from "@/lib/prisma/queries/notifications"; import { secureLogger } from "@/lib/secure-logger"; /** * POST /api/listings/[id]/bid * Coloca um lance em um leilão */ export async function POST( request: NextRequest, { params }: { params: Promise<{ id: string }> }, ) { try { const authResult = await requireAuth(request); if (authResult instanceof NextResponse) return authResult; const auth = authResult; const { id } = await params; const listingId = parseInt(id, 10); if (Number.isNaN(listingId)) { return NextResponse.json( { success: false, error: "ID de anúncio inválido" }, { status: 400 }, ); } const body = await request.json(); const { amount, payment_method } = body; if (!amount || typeof amount !== "number" || amount <= 0) { return NextResponse.json( { success: false, error: "Valor do lance é obrigatório e deve ser maior que zero", }, { status: 400 }, ); } if (!payment_method || !["pix", "tc", "gp"].includes(payment_method)) { return NextResponse.json( { success: false, error: "Método de pagamento inválido" }, { status: 400 }, ); } // Colocar lance const result = await placeBid( listingId, auth.userId, amount, payment_method, ); if (!result.success) { return NextResponse.json( { success: false, error: result.error }, { status: 400 }, ); } // Garantir existência do anúncio e vendedor antes de notificar const listing = result.listing; if (!listing) { return NextResponse.json( { success: false, error: "Anúncio não encontrado após registrar o lance" }, { status: 404 }, ); } if (typeof listing.seller_id !== "number") { secureLogger.warn("SellerId inválido ao criar notificação de lance", { listingId, sellerId: listing.seller_id, }); return NextResponse.json( { success: false, error: "Vendedor inválido para notificação" }, { status: 500 }, ); } // Criar notificação para o vendedor await createNotification({ user_id: listing.seller_id, notification_type: "bid", title: "Novo lance!", message: `Novo lance de R$ ${amount.toFixed(2)} no item "${listing.item_name}"`, related_id: listingId, send_whatsapp: false, }); // Se havia um lanceador anterior, notificar que foi superado if (result.previousBidderId) { await createNotification({ user_id: result.previousBidderId, notification_type: "bid", title: "Lance superado", message: `Seu lance foi superado no item "${listing.item_name}"`, related_id: listingId, send_whatsapp: false, }); } // Registrar telemetria const { trackEvent } = await import("@/lib/prisma/queries/telemetry"); await trackEvent({ event_type: "bid_placed", ad_id: listingId, user_id: auth.userId, metadata: { bid_amount: amount, payment_method: payment_method, previous_bid: listing.current_bid_amount ? Number(listing.current_bid_amount) : null, min_increment: listing.min_bid_increment ? Number(listing.min_bid_increment) : null, }, }); secureLogger.info("✅ Lance realizado com sucesso", { userId: auth.userId, listingId, amount, paymentMethod: payment_method, }); return NextResponse.json( { success: true, listing: result.listing, message: "Lance realizado com sucesso", }, { status: 200 }, ); } catch (error) { secureLogger.error("❌ Erro ao processar lance", { error: error instanceof Error ? error.message : "Erro desconhecido", stack: error instanceof Error ? error.stack : undefined, }); return NextResponse.json( { success: false, error: "Erro ao processar lance" }, { status: 500 }, ); } }