import { sql } from '@vercel/postgres'; import { verifyToken } from '../auth-utils.js'; // GET /api/cards - Search cards from database export default async function handler(req, res) { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // Handle preflight requests if (req.method === 'OPTIONS') { res.status(200).end(); return; } if (req.method !== 'GET' && req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); } try { const { q, search, game, page = '1', limit = '20' } = req.query; const query = q || search || ''; const pageNum = parseInt(page); const limitNum = parseInt(limit); const offset = (pageNum - 1) * limitNum; console.log(`🔍 Searching cards: "${query}" game: "${game}" page: ${pageNum}`); // Build the SQL query let sqlQuery = ` SELECT id, name, set_name, set_code, card_number, rarity, game, mana_cost, cmc, card_type, colors, oracle_text, power, toughness, image_url, stock_image_url, current_price, market_price, verified, created_at, updated_at FROM cards WHERE 1=1 `; const params = []; let paramIndex = 1; // Add search filter if (query.trim()) { sqlQuery += ` AND ( name ILIKE $${paramIndex} OR oracle_text ILIKE $${paramIndex} OR card_type ILIKE $${paramIndex} OR set_name ILIKE $${paramIndex} )`; params.push(`%${query}%`); paramIndex++; } // Add game filter if (game && game !== 'ALL') { sqlQuery += ` AND game = $${paramIndex}`; params.push(game); paramIndex++; } // Add ordering and pagination sqlQuery += ` ORDER BY name ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`; params.push(limitNum, offset); console.log(`📝 SQL Query: ${sqlQuery}`); console.log(`📝 Parameters:`, params); // Execute the query const result = await sql.query(sqlQuery, params); // Get total count for pagination let countQuery = ` SELECT COUNT(*) as total FROM cards WHERE 1=1 `; const countParams = []; let countParamIndex = 1; if (query.trim()) { countQuery += ` AND ( name ILIKE $${countParamIndex} OR oracle_text ILIKE $${countParamIndex} OR card_type ILIKE $${countParamIndex} OR set_name ILIKE $${countParamIndex} )`; countParams.push(`%${query}%`); countParamIndex++; } if (game && game !== 'ALL') { countQuery += ` AND game = $${countParamIndex}`; countParams.push(game); countParamIndex++; } const countResult = await sql.query(countQuery, countParams); const total = parseInt(countResult.rows[0].total); // Format the response const cards = result.rows.map(card => ({ id: card.id, name: card.name, setName: card.set_name, setCode: card.set_code, cardNumber: card.card_number, rarity: card.rarity, game: card.game, manaCost: card.mana_cost, cmc: card.cmc, cardType: card.card_type, colors: card.colors ? JSON.parse(card.colors) : [], oracleText: card.oracle_text, power: card.power, toughness: card.toughness, imageUrl: card.image_url, stockImageUrl: card.stock_image_url, currentPrice: card.current_price, marketPrice: card.market_price, verified: card.verified, createdAt: card.created_at, updatedAt: card.updated_at })); return res.status(200).json({ success: true, cards, pagination: { page: pageNum, limit: limitNum, total, pages: Math.ceil(total / limitNum) } }); } catch (error) { console.error('❌ Error in cards API:', error); return res.status(500).json({ error: 'Failed to search cards', details: error.message }); } }