import { NextResponse } from 'next/server'; import { sql } from '@vercel/postgres'; import { verifyToken } from '../setup-auth.js'; // GET /api/cards - Search cards from database export async function GET(request) { try { const { searchParams } = new URL(request.url); const query = searchParams.get('q') || searchParams.get('search') || ''; const game = searchParams.get('game'); const page = parseInt(searchParams.get('page') || '1'); const limit = parseInt(searchParams.get('limit') || '20'); const offset = (page - 1) * limit; console.log(`🔍 Searching cards: "${query}" game: "${game}" page: ${page}`); // 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(limit, 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); // Transform the results const cards = result.rows.map(row => ({ id: row.id, name: row.name, set_name: row.set_name, set_code: row.set_code, card_number: row.card_number, rarity: row.rarity, game: row.game, mana_cost: row.mana_cost, cmc: row.cmc, card_type: row.card_type, colors: row.colors ? JSON.parse(row.colors) : [], oracle_text: row.oracle_text, power: row.power, toughness: row.toughness, image_url: row.image_url, stock_image_url: row.stock_image_url, current_price: row.current_price, market_price: row.market_price, verified: row.verified, createdAt: row.created_at, updatedAt: row.updated_at, })); console.log(`✅ Found ${cards.length} cards (total: ${total})`); return NextResponse.json({ success: true, data: cards, pagination: { page, limit, total, totalPages: Math.ceil(total / limit), hasNext: page * limit < total, hasPrev: page > 1 }, search: { query, game, results: cards.length } }); } catch (error) { console.error('❌ Error searching cards:', error); return NextResponse.json( { error: 'Failed to search cards', details: error.message }, { status: 500 } ); } } // POST /api/cards - Find or create card export async function POST(request) { try { const token = request.headers.get('authorization')?.replace('Bearer ', ''); const user = await verifyToken(token); if (!user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { name, game, set_name, set_code, card_number } = await request.json(); if (!name || !game) { return NextResponse.json({ error: 'Name and game are required' }, { status: 400 }); } console.log(`🔍 Finding or creating card: "${name}" (${game})`); // Try to find existing card let result = await sql.query(` SELECT * FROM cards WHERE name = $1 AND game = $2 ORDER BY created_at DESC LIMIT 1 `, [name, game]); if (result.rows.length > 0) { const card = result.rows[0]; console.log(`✅ Found existing card: ${card.name}`); return NextResponse.json({ success: true, data: { id: card.id, name: card.name, set_name: card.set_name, set_code: card.set_code, card_number: card.card_number, rarity: card.rarity, game: card.game, mana_cost: card.mana_cost, cmc: card.cmc, card_type: card.card_type, colors: card.colors ? JSON.parse(card.colors) : [], oracle_text: card.oracle_text, power: card.power, toughness: card.toughness, image_url: card.image_url, stock_image_url: card.stock_image_url, current_price: card.current_price, market_price: card.market_price, verified: card.verified, createdAt: card.created_at, updatedAt: card.updated_at, }, message: 'Card found' }); } // Create new card if not found console.log(`➕ Creating new card: ${name}`); result = await sql.query(` INSERT INTO cards ( name, game, set_name, set_code, card_number, verified ) VALUES ($1, $2, $3, $4, $5, $6) RETURNING * `, [name, game, set_name || '', set_code || '', card_number || '', false]); const newCard = result.rows[0]; return NextResponse.json({ success: true, data: { id: newCard.id, name: newCard.name, set_name: newCard.set_name, set_code: newCard.set_code, card_number: newCard.card_number, rarity: newCard.rarity, game: newCard.game, mana_cost: newCard.mana_cost, cmc: newCard.cmc, card_type: newCard.card_type, colors: newCard.colors ? JSON.parse(newCard.colors) : [], oracle_text: newCard.oracle_text, power: newCard.power, toughness: newCard.toughness, image_url: newCard.image_url, stock_image_url: newCard.stock_image_url, current_price: newCard.current_price, market_price: newCard.market_price, verified: newCard.verified, createdAt: newCard.created_at, updatedAt: newCard.updated_at, }, message: 'Card created' }); } catch (error) { console.error('❌ Error finding/creating card:', error); return NextResponse.json( { error: 'Failed to find/create card', details: error.message }, { status: 500 } ); } }