const { Pool } = require('pg'); const jwt = require('jsonwebtoken'); const pool = new Pool({ connectionString: process.env.DATABASE_URL, ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false, }); // Middleware to verify user authentication function verifyAuth(req) { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { throw new Error('No token provided'); } const token = authHeader.substring(7); const jwtSecret = process.env.JWT_SECRET || 'fallback-secret-change-in-production'; try { const decoded = jwt.verify(token, jwtSecret); return decoded; } catch (error) { throw new Error('Invalid token'); } } export default async function handler(req, res) { if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); } const client = await pool.connect(); try { // Verify authentication const user = verifyAuth(req); const { collectionId, cardId, quantity = 1, condition = 'near-mint', notes = null, purchasePrice = null } = req.body; // Validate required fields if (!collectionId || !cardId) { return res.status(400).json({ error: 'Collection ID and Card ID are required' }); } // Verify collection ownership const collectionCheck = await client.query( 'SELECT id, name FROM user_collections WHERE id = $1 AND user_id = $2', [collectionId, user.userId] ); if (collectionCheck.rows.length === 0) { return res.status(404).json({ error: 'Collection not found or access denied' }); } // Verify card exists const cardCheck = await client.query( 'SELECT id, name, game, rarity, current_price FROM cards WHERE id = $1', [cardId] ); if (cardCheck.rows.length === 0) { return res.status(404).json({ error: 'Card not found' }); } const card = cardCheck.rows[0]; const collection = collectionCheck.rows[0]; // Check if card already exists in collection with same condition const existingCard = await client.query(` SELECT id, quantity FROM collection_cards WHERE collection_id = $1 AND card_id = $2 AND condition = $3 `, [collectionId, cardId, condition]); let result; if (existingCard.rows.length > 0) { // Update existing entry - increase quantity const newQuantity = existingCard.rows[0].quantity + quantity; await client.query(` UPDATE collection_cards SET quantity = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2 `, [newQuantity, existingCard.rows[0].id]); result = { action: 'updated', previousQuantity: existingCard.rows[0].quantity, newQuantity: newQuantity }; } else { // Create new collection card entry const insertResult = await client.query(` INSERT INTO collection_cards ( collection_id, card_id, quantity, condition, notes, purchase_price ) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id, added_at `, [collectionId, cardId, quantity, condition, notes, purchasePrice]); result = { action: 'added', collectionCardId: insertResult.rows[0].id, addedAt: insertResult.rows[0].added_at }; } // Get updated collection stats const statsQuery = await client.query(` SELECT COUNT(cc.id) as total_entries, COALESCE(SUM(cc.quantity), 0) as total_cards, COALESCE(SUM(cc.quantity * COALESCE(c.current_price, 0)), 0) as total_value FROM collection_cards cc LEFT JOIN cards c ON cc.card_id = c.id WHERE cc.collection_id = $1 `, [collectionId]); const stats = statsQuery.rows[0]; res.status(200).json({ success: true, message: `Card ${result.action} successfully`, result: { ...result, card: { id: card.id, name: card.name, game: card.game, rarity: card.rarity, currentPrice: card.current_price }, collection: { id: collection.id, name: collection.name }, quantity: quantity, condition: condition, collectionStats: { totalEntries: parseInt(stats.total_entries), totalCards: parseInt(stats.total_cards), totalValue: parseFloat(stats.total_value) } } }); } catch (error) { console.error('Add card to collection error:', error); if (error.message === 'No token provided' || error.message === 'Invalid token') { res.status(401).json({ error: error.message }); } else { res.status(500).json({ error: 'Internal server error', details: error.message }); } } finally { client.release(); } }