import { sql } from '../../../lib/sql.js'; import { getUserFromRequest } from '../../../lib/permission-middleware'; import { validatePalette, validateLayout, DEFAULT_LAYOUT } from '../../../lib/frame-palette.js'; export default async function handler(req, res) { try { const user = await getUserFromRequest(req); if (!user) { return res.status(401).json({ error: 'Authentication required' }); } const frameId = parseInt(req.query.id, 10); if (!Number.isInteger(frameId)) { return res.status(400).json({ error: 'Invalid frame id' }); } const found = await sql` SELECT * FROM custom_frames WHERE id = ${frameId} AND user_id = ${user.userId} `; if (found.rows.length === 0) { return res.status(404).json({ error: 'Frame not found' }); } if (req.method === 'GET') { return res.status(200).json({ frame: found.rows[0] }); } if (req.method === 'PUT') { const name = typeof req.body?.name === 'string' ? req.body.name.trim() : ''; if (!name || name.length > 100) { return res.status(400).json({ error: 'Frame name is required (100 characters max)' }); } const { palette, error } = validatePalette(req.body?.palette); if (error) { return res.status(400).json({ error }); } const clash = await sql` SELECT id FROM custom_frames WHERE user_id = ${user.userId} AND lower(name) = ${name.toLowerCase()} AND id <> ${frameId} `; if (clash.rows.length > 0) { return res.status(409).json({ error: 'You already have a frame with that name' }); } const textureUrl = req.body?.texture_url === null || req.body?.texture_url === '' ? null : typeof req.body?.texture_url === 'string' ? req.body.texture_url.trim() : found.rows[0].texture_url; const layoutInput = req.body?.layout === undefined ? found.rows[0].layout : req.body.layout; const { layout, error: layoutError } = validateLayout(layoutInput || {}); if (layoutError) { return res.status(400).json({ error: layoutError }); } const updated = await sql` UPDATE custom_frames SET name = ${name}, palette = ${sql.json(palette)}, texture_url = ${textureUrl}, layout = ${sql.json(layout)}, updated_at = CURRENT_TIMESTAMP WHERE id = ${frameId} RETURNING id, name, palette, texture_url, frame_image_url, layout, created_at, updated_at `; return res.status(200).json({ frame: updated.rows[0] }); } if (req.method === 'DELETE') { // Designs using this frame fall back to their starter frame_id // (custom_frame_id drops to NULL via FK). await sql`DELETE FROM custom_frames WHERE id = ${frameId}`; return res.status(200).json({ message: 'Frame deleted' }); } return res.status(405).json({ error: 'Method not allowed' }); } catch (error) { console.error('Custom frame API error:', error); return res.status(500).json({ error: 'Internal server error' }); } }