const express = require('express'); const router = express.Router(); const db = require('../database'); // ================================================================ // GET /api/gtos — listar GTOs com filtros e paginação // Query params: // search — busca por patient_name ou gto_number (ILIKE) // filter — 'all' | 'vinculada' | 'enviada' // page — número da página (default 1) // limit — itens por página (default 20) // ================================================================ router.get('/', async (req, res) => { try { const search = (req.query.search || '').trim(); const filter = req.query.filter || 'all'; const page = Math.max(1, parseInt(req.query.page) || 1); const limit = Math.min(100, parseInt(req.query.limit) || 20); const offset = (page - 1) * limit; let params = []; let where = []; let i = 1; if (search) { where.push(`(g.patient_name ILIKE $${i} OR g.gto_number ILIKE $${i})`); params.push(`%${search}%`); i++; } if (filter === 'vinculada') { where.push(`EXISTS (SELECT 1 FROM gto_images gi2 WHERE gi2.gto_id = g.id)`); } else if (filter === 'enviada') { where.push(`g.sent = TRUE`); } const whereClause = where.length ? `WHERE ${where.join(' AND ')}` : ''; // Total para paginação const countRow = await db.get( `SELECT COUNT(*) as total FROM gtos g ${whereClause}`, params ); const total = parseInt(countRow.total); const rows = await db.all( `SELECT g.*, COUNT(gi.id)::int AS image_count FROM gtos g LEFT JOIN gto_images gi ON gi.gto_id = g.id ${whereClause} GROUP BY g.id ORDER BY g.created_at DESC LIMIT ${limit} OFFSET ${offset}`, params ); // Adiciona thumb_url da primeira imagem vinculada para preview for (const row of rows) { if (parseInt(row.image_count) > 0) { const firstImg = await db.get( `SELECT i.id FROM gto_images gi JOIN images i ON i.id = gi.image_id WHERE gi.gto_id = $1 ORDER BY gi.created_at ASC LIMIT 1`, [row.id] ); row.thumb_url = firstImg ? `/api/images/${firstImg.id}/thumbnail` : null; } else { row.thumb_url = null; } } res.json({ rows, total, page, limit, pages: Math.ceil(total / limit) }); } catch (err) { console.error('Erro ao listar GTOs:', err); res.status(500).json({ error: err.message }); } }); // ================================================================ // GET /api/gtos/:id — detalhe de uma GTO com imagens vinculadas // ================================================================ router.get('/:id', async (req, res) => { try { const gto = await db.get('SELECT * FROM gtos WHERE id = $1', [req.params.id]); if (!gto) return res.status(404).json({ error: 'GTO não encontrada' }); const images = await db.all( `SELECT i.*, gi.id as link_id FROM gto_images gi JOIN images i ON i.id = gi.image_id WHERE gi.gto_id = $1 ORDER BY gi.created_at DESC`, [req.params.id] ); res.json({ ...gto, images }); } catch (err) { console.error('Erro ao buscar GTO:', err); res.status(500).json({ error: err.message }); } }); // ================================================================ // POST /api/gtos — criar nova GTO // Body: { gto_number, patient_name, description } // ================================================================ router.post('/', async (req, res) => { try { const { gto_number, patient_name, description } = req.body; if (!gto_number || !patient_name) { return res.status(400).json({ error: 'gto_number e patient_name são obrigatórios' }); } const result = await db.run( `INSERT INTO gtos (gto_number, patient_name, description) VALUES ($1, $2, $3) RETURNING id`, [gto_number.trim(), patient_name.trim(), description || ''] ); const gto = await db.get('SELECT * FROM gtos WHERE id = $1', [result.lastID]); res.status(201).json(gto); } catch (err) { console.error('Erro ao criar GTO:', err); res.status(500).json({ error: err.message }); } }); // ================================================================ // PUT /api/gtos/:id — atualizar GTO // ================================================================ router.put('/:id', async (req, res) => { try { const { gto_number, description } = req.body; await db.run( `UPDATE gtos SET gto_number = $1, description = $2 WHERE id = $3`, [gto_number, description || '', req.params.id] ); const gto = await db.get('SELECT * FROM gtos WHERE id = $1', [req.params.id]); res.json(gto); } catch (err) { res.status(500).json({ error: err.message }); } }); // ================================================================ // DELETE /api/gtos/:id — remover GTO e vínculos // ================================================================ router.delete('/:id', async (req, res) => { try { await db.run('DELETE FROM gto_images WHERE gto_id = $1', [req.params.id]); await db.run('DELETE FROM gtos WHERE id = $1', [req.params.id]); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); // ================================================================ // POST /api/gtos/:id/images — vincular imagem à GTO // Body: { image_id } // ================================================================ router.post('/:id/images', async (req, res) => { try { const { image_id } = req.body; if (!image_id) return res.status(400).json({ error: 'image_id é obrigatório' }); // Verificar se já está vinculada const existing = await db.get( 'SELECT id FROM gto_images WHERE gto_id = $1 AND image_id = $2', [req.params.id, image_id] ); if (existing) return res.status(409).json({ error: 'Imagem já vinculada a esta GTO' }); await db.run( 'INSERT INTO gto_images (gto_id, image_id) VALUES ($1, $2) RETURNING id', [req.params.id, image_id] ); res.status(201).json({ success: true, message: 'Imagem vinculada à GTO' }); } catch (err) { console.error('Erro ao vincular imagem:', err); res.status(500).json({ error: err.message }); } }); // ================================================================ // DELETE /api/gtos/:id/images/:imageId — desvincular imagem // ================================================================ router.delete('/:id/images/:imageId', async (req, res) => { try { await db.run( 'DELETE FROM gto_images WHERE gto_id = $1 AND image_id = $2', [req.params.id, req.params.imageId] ); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); // ================================================================ // POST /api/gtos/:id/sent — marcar/desmarcar GTO como enviada // Body: { sent: true|false } // ================================================================ router.post('/:id/sent', async (req, res) => { try { const sent = req.body.sent !== false; // default true await db.run( 'UPDATE gtos SET sent = $1, sent_at = CASE WHEN $1 THEN NOW() ELSE NULL END WHERE id = $2', [sent, req.params.id] ); const gto = await db.get('SELECT * FROM gtos WHERE id = $1', [req.params.id]); res.json(gto); } catch (err) { console.error('Erro ao marcar GTO como enviada:', err); res.status(500).json({ error: err.message }); } }); module.exports = router;