import { Router } from 'express' import { nanoid } from 'nanoid' import { getDb } from '../db/connection.js' import { adminAuth } from '../middleware/adminAuth.js' import { requireBody, sanitizeString, sanitizeInt } from '../middleware/validate.js' import { rowToProduct } from './products.js' export const adminProductsRouter = Router() adminProductsRouter.use(adminAuth) interface ProductRow { id: string; name: string; slug: string; description: string; price_sats: number; images: string; sizes: string; category: string; is_active: number; created_at: string; updated_at: string } adminProductsRouter.get('/', (_req, res) => { const db = getDb() const rows = db.prepare('SELECT * FROM products ORDER BY created_at DESC').all() as ProductRow[] res.json(rows.map(rowToProduct)) }) adminProductsRouter.post('/', requireBody('name', 'slug', 'priceSats'), (req, res) => { const db = getDb() const { name, slug, description, priceSats, images, sizes, category } = req.body const price = sanitizeInt(priceSats) if (price === null || price <= 0) { res.status(400).json({ error: { code: 'INVALID_PRICE', message: 'Price must be a positive integer (sats)' } }); return } const id = nanoid() try { db.prepare('INSERT INTO products (id, name, slug, description, price_sats, images, sizes, category) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(id, sanitizeString(name), sanitizeString(slug), sanitizeString(description || ''), price, JSON.stringify(images || []), JSON.stringify(sizes || []), sanitizeString(category || 'general')) const row = db.prepare('SELECT * FROM products WHERE id = ?').get(id) as ProductRow res.status(201).json(rowToProduct(row)) } catch (err: unknown) { if (err instanceof Error && err.message.includes('UNIQUE')) { res.status(409).json({ error: { code: 'SLUG_EXISTS', message: 'A product with this slug already exists' } }); return } throw err } }) adminProductsRouter.put('/:id', (req, res) => { const db = getDb() const { name, slug, description, priceSats, images, sizes, category, isActive } = req.body const existing = db.prepare('SELECT id FROM products WHERE id = ?').get(req.params.id) if (!existing) { res.status(404).json({ error: { code: 'NOT_FOUND', message: 'Product not found' } }); return } const price = sanitizeInt(priceSats) if (price !== null && price <= 0) { res.status(400).json({ error: { code: 'INVALID_PRICE', message: 'Price must be a positive integer (sats)' } }); return } try { db.prepare("UPDATE products SET name = COALESCE(?, name), slug = COALESCE(?, slug), description = COALESCE(?, description), price_sats = COALESCE(?, price_sats), images = COALESCE(?, images), sizes = COALESCE(?, sizes), category = COALESCE(?, category), is_active = COALESCE(?, is_active), updated_at = datetime('now') WHERE id = ?").run(name ? sanitizeString(name) : null, slug ? sanitizeString(slug) : null, description !== undefined ? sanitizeString(description) : null, price, images ? JSON.stringify(images) : null, sizes ? JSON.stringify(sizes) : null, category ? sanitizeString(category) : null, isActive !== undefined ? (isActive ? 1 : 0) : null, req.params.id) const row = db.prepare('SELECT * FROM products WHERE id = ?').get(req.params.id) as ProductRow res.json(rowToProduct(row)) } catch (err: unknown) { if (err instanceof Error && err.message.includes('UNIQUE')) { res.status(409).json({ error: { code: 'SLUG_EXISTS', message: 'A product with this slug already exists' } }); return } throw err } }) adminProductsRouter.delete('/:id', (req, res) => { const db = getDb() const result = db.prepare("UPDATE products SET is_active = 0, updated_at = datetime('now') WHERE id = ?").run(req.params.id) if (result.changes === 0) { res.status(404).json({ error: { code: 'NOT_FOUND', message: 'Product not found' } }); return } res.json({ ok: true }) }) adminProductsRouter.patch('/:id/stock', requireBody('sizes'), (req, res) => { const db = getDb() const { sizes } = req.body if (!Array.isArray(sizes)) { res.status(400).json({ error: { code: 'INVALID_SIZES', message: 'Sizes must be an array' } }); return } const result = db.prepare("UPDATE products SET sizes = ?, updated_at = datetime('now') WHERE id = ?").run(JSON.stringify(sizes), req.params.id) if (result.changes === 0) { res.status(404).json({ error: { code: 'NOT_FOUND', message: 'Product not found' } }); return } const row = db.prepare('SELECT * FROM products WHERE id = ?').get(req.params.id) as ProductRow res.json(rowToProduct(row)) })