import { type NextRequest, NextResponse } from "next/server"; import { requireAuth } from "@/lib/auth/middleware"; import { prisma } from "@/lib/prisma/app"; import { getPurchaseIntentionsByBuyer } from "@/lib/prisma/queries/purchase-intentions"; import { trackEvent } from "@/lib/prisma/queries/telemetry"; import { secureLogger } from "@/lib/secure-logger"; /** * GET /api/purchase-intentions/my * Lista todas as intenções de compra do usuário autenticado */ export async function GET(request: NextRequest) { try { const authResult = await requireAuth(request); if (authResult instanceof NextResponse) return authResult; const auth = authResult; // Buscar parâmetros de filtro const { searchParams } = new URL(request.url); const status = searchParams.get("status") as | "pending" | "accepted" | "rejected" | "expired" | "completed" | null; const limit = parseInt(searchParams.get("limit") || "100", 10); // Buscar intenções do comprador const intentions = await getPurchaseIntentionsByBuyer(auth.userId, { status: status || undefined, limit, }); // Buscar todos os listings de uma vez (otimização) const listingIds = [...new Set(intentions.map((i) => i.listing_id))]; const listings = await prisma.listing.findMany({ where: { listing_id: { in: listingIds } }, select: { listing_id: true, item_id: true, item_id_unified: true, item_name: true, quantity: true, server_name: true, seller_id: true, price_pix: true, price_tibia_coins: true, price_gold_coins: true, listing_status: true, created_at: true, description: true, trade_item_id: true, trade_item_name: true, trade_item_quantity: true, views_count: true, favorites_count: true, is_featured: true, item: { select: { image_url: true, image_local_path: true, category: true, }, }, seller: { select: { user_id: true, username: true, email: true, }, }, }, }); // Criar mapa de listings para acesso rápido const listingsMap = new Map(listings.map((l) => [l.listing_id, l])); // Buscar character names dos vendedores em batch const sellerServerPairs = [ ...new Set(listings.map((l) => `${l.seller_id}:${l.server_name}`)), ]; const characterMap = new Map(); await Promise.all( sellerServerPairs.map(async (pair) => { const [sellerId, serverName] = pair.split(":"); const character = await prisma.userCharacter.findFirst({ where: { user_id: parseInt(sellerId, 10), server_name: serverName, is_main: true, }, select: { character_name: true, }, }); characterMap.set(pair, character?.character_name || null); }), ); // Serializar datas para string const serializeDate = (date: Date | null): string | null => { return date ? new Date(date).toISOString() : null; }; // Expandir dados do listing para cada intenção const intentionsWithListingDetails = intentions.map((intention) => { const listing = listingsMap.get(intention.listing_id); const characterKey = listing ? `${listing.seller_id}:${listing.server_name}` : null; const sellerCharacterName = characterKey ? characterMap.get(characterKey) || null : null; const chatId = listing?.seller_id != null ? `${intention.listing_id}_${intention.buyer_id}_${listing.seller_id}` : null; return { ...intention, created_at: serializeDate(intention.created_at as Date) || intention.created_at, updated_at: serializeDate(intention.updated_at as Date) || intention.updated_at, expires_at: serializeDate(intention.expires_at as Date | null), accepted_at: serializeDate(intention.accepted_at as Date | null), rejected_at: serializeDate(intention.rejected_at as Date | null), chat_id: chatId, listing: listing ? { listing_id: listing.listing_id, item_id: listing.item_id, item_id_unified: listing.item_id_unified, item_name: listing.item_name, quantity: listing.quantity, server_name: listing.server_name, seller_id: listing.seller_id, price_pix: listing.price_pix ? Number(listing.price_pix) : null, price_tibia_coins: listing.price_tibia_coins !== null && listing.price_tibia_coins !== undefined ? Number(listing.price_tibia_coins) : null, price_gold_coins: listing.price_gold_coins ? Number(listing.price_gold_coins) : null, listing_status: listing.listing_status, created_at: listing.created_at instanceof Date ? listing.created_at.toISOString() : listing.created_at, description: listing.description, trade_item_id: listing.trade_item_id, trade_item_name: listing.trade_item_name, trade_item_quantity: listing.trade_item_quantity, views_count: listing.views_count ?? 0, favorites_count: listing.favorites_count ?? 0, is_featured: listing.is_featured ?? false, image_url: listing.item?.image_url || null, image_local_path: listing.item?.image_local_path || null, item_category: listing.item?.category || null, seller_character_name: sellerCharacterName, seller_username: listing.seller?.username || null, seller_email: listing.seller?.email || null, } : null, }; }); // Registrar telemetria await trackEvent({ event_type: "purchase_intention_viewed", user_id: auth.userId, metadata: { intentions_count: intentionsWithListingDetails.length, filter_status: status || "all", }, }); return NextResponse.json( { success: true, intentions: intentionsWithListingDetails, count: intentionsWithListingDetails.length, }, { status: 200 }, ); } catch (error) { secureLogger.error("❌ Erro ao buscar intenções de compra do usuário", { 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ções de compra" }, { status: 500 }, ); } }