import { sql } from '@vercel/postgres'; import { getUserFromRequest } from '../../../lib/permission-middleware'; export default async function handler(req, res) { // Set CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, 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') { return res.status(405).json({ error: 'Method not allowed' }); } try { // Get authenticated user const user = await getUserFromRequest(req); if (!user) { return res.status(401).json({ error: 'Authentication required' }); } const { search = '', tcg = 'all', rarity = 'all', set = 'all', valueRange = 'all', page = '1', limit = '50' } = req.query; const pageNum = parseInt(page) || 1; const limitNum = parseInt(limit) || 50; const offset = (pageNum - 1) * limitNum; // Build WHERE conditions let whereConditions = ['uc.user_id = $1']; let params = [user.userId]; let paramIndex = 2; if (search.trim()) { whereConditions.push(`c.name ILIKE $${paramIndex}`); params.push(`%${search.trim()}%`); paramIndex++; } if (tcg !== 'all') { whereConditions.push(`c.game = $${paramIndex}`); params.push(tcg); paramIndex++; } if (rarity !== 'all') { whereConditions.push(`c.rarity = $${paramIndex}`); params.push(rarity); paramIndex++; } if (set !== 'all') { whereConditions.push(`c.set_name = $${paramIndex}`); params.push(set); paramIndex++; } if (valueRange !== 'all') { // Handle value range filtering const ranges = { 'under-1': [0, 1], '1-5': [1, 5], '5-25': [5, 25], '25-100': [25, 100], 'over-100': [100, 999999] }; if (ranges[valueRange]) { const [min, max] = ranges[valueRange]; if (valueRange === 'over-100') { whereConditions.push(`c.market_price >= $${paramIndex}`); params.push(min); paramIndex++; } else { whereConditions.push(`c.market_price >= $${paramIndex} AND c.market_price <= $${paramIndex + 1}`); params.push(min, max); paramIndex += 2; } } } const whereClause = whereConditions.join(' AND '); // Get owned cards with user ownership data const cardsQuery = ` SELECT c.id, c.name, c.set_name, c.set_code, c.card_number, c.rarity, c.game, c.mana_cost, c.cmc, c.card_type, c.colors, c.oracle_text, c.power, c.toughness, c.image_url, c.stock_image_url, c.current_price, c.market_price, c.scryfall_id, c.verified, uc.quantity as owned_quantity, uc.condition, uc.created_at as owned_since FROM cards c INNER JOIN user_cards uc ON c.id = uc.card_id WHERE ${whereClause} ORDER BY c.name ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1} `; const countQuery = ` SELECT COUNT(*) as total FROM cards c INNER JOIN user_cards uc ON c.id = uc.card_id WHERE ${whereClause} `; // Execute queries const result = await sql.query(cardsQuery, [...params, limitNum, offset]); const countResult = await sql.query(countQuery, params); const total = parseInt(countResult.rows[0].total); const totalPages = Math.ceil(total / limitNum); // Get filter options for owned cards only const filtersQuery = ` SELECT DISTINCT c.game, c.rarity, c.set_name FROM cards c INNER JOIN user_cards uc ON c.id = uc.card_id WHERE uc.user_id = $1 ORDER BY c.game, c.rarity, c.set_name `; const filtersResult = await sql.query(filtersQuery, [user.userId]); const games = [...new Set(filtersResult.rows.map(row => row.game))].filter(Boolean); const rarities = [...new Set(filtersResult.rows.map(row => row.rarity))].filter(Boolean); const sets = [...new Set(filtersResult.rows.map(row => row.set_name))].filter(Boolean); res.status(200).json({ cards: result.rows, pagination: { page: pageNum, limit: limitNum, total, pages: totalPages }, filters: { games, rarities, sets } }); } catch (error) { console.error('Error fetching owned cards:', error); res.status(500).json({ error: 'Internal server error' }); } }