import { sql } from '../../../lib/sql.js'; import { getUserFromRequest } from '../../../lib/permission-middleware'; import { pickDesignFields } from '../../../lib/custom-cards-fields.js'; const CUSTOM_GAME = 'Custom'; const CUSTOM_SET = 'Designs'; export default async function handler(req, res) { try { const user = await getUserFromRequest(req); if (!user) { return res.status(401).json({ error: 'Authentication required' }); } if (req.method === 'GET') { const result = await sql` SELECT id, card_id, name, mana_cost, card_type, rarity, rules_text, actions, flavor_quote, power, toughness, frame_id, artwork_url, art_mode, created_at, updated_at FROM custom_cards WHERE user_id = ${user.userId} ORDER BY updated_at DESC `; return res.status(200).json({ designs: result.rows }); } if (req.method === 'POST') { const design = await createDesign(user.userId, req.body); if (!design) { return res.status(400).json({ error: 'Name is required' }); } return res.status(201).json({ design }); } return res.status(405).json({ error: 'Method not allowed' }); } catch (error) { console.error('Custom cards API error:', error); return res.status(500).json({ error: 'Internal server error' }); } } async function createDesign(userId, body) { const f = pickDesignFields(body); if (!f.name) return null; const inserted = await sql` INSERT INTO custom_cards (user_id, name, mana_cost, card_type, rarity, rules_text, actions, flavor_quote, power, toughness, frame_id, artwork_url, art_mode) VALUES (${userId}, ${f.name}, ${f.manaCost}, ${f.cardType}, ${f.rarity}, ${f.rulesText}, ${f.actions}, ${f.flavorQuote}, ${f.power}, ${f.toughness}, ${f.frameId}, ${f.artworkUrl}, ${f.artMode}) RETURNING * `; const design = inserted.rows[0]; // Mirror into the shared catalog so the design shows up in My Cards, // lists, and decks through the normal card joins. const cardId = await syncCatalogCard(design, f); if (cardId) { await ensureOwnedRow(userId, cardId); const linked = await sql` UPDATE custom_cards SET card_id = ${cardId} WHERE id = ${design.id} RETURNING * `; return linked.rows[0]; } return design; } /** Create/update the catalog twin of a custom design; returns card id. */ export async function syncCatalogCard(design, fields) { const values = { name: fields.name, setName: CUSTOM_SET, setCode: 'DSGN', rarity: fields.rarity, game: CUSTOM_GAME, manaCost: fields.manaCost, cardType: fields.cardType, oracleText: [fields.actions, fields.rulesText, fields.flavorQuote] .filter(Boolean) .join('\n\n') || null, imageUrl: fields.artworkUrl, }; if (design.card_id) { const updated = await sql` UPDATE cards SET name = ${values.name}, set_name = ${values.setName}, set_code = ${values.setCode}, rarity = ${values.rarity}, mana_cost = ${values.manaCost}, card_type = ${values.cardType}, oracle_text = ${values.oracleText}, image_url = ${values.imageUrl}, updated_at = CURRENT_TIMESTAMP WHERE id = ${design.card_id} RETURNING id `; if (updated.rows.length > 0) return updated.rows[0].id; } const inserted = await sql` INSERT INTO cards (name, set_name, set_code, rarity, game, mana_cost, card_type, oracle_text, image_url) VALUES (${values.name}, ${values.setName}, ${values.setCode}, ${values.rarity}, ${values.game}, ${values.manaCost}, ${values.cardType}, ${values.oracleText}, ${values.imageUrl}) RETURNING id `; return inserted.rows[0].id; } /** Idempotently give the designer one copy of their own creation. */ export async function ensureOwnedRow(userId, cardId) { await sql` INSERT INTO user_cards (user_id, card_id, quantity) VALUES (${userId}, ${cardId}, 1) ON CONFLICT (user_id, card_id, is_foil) DO NOTHING `; }