const express = require('express'); const router = express.Router(); const { query } = require('../config/database'); const { authenticateToken } = require('../middleware/auth'); // LISTAR DISPOSITIVOS router.get('/', authenticateToken, async (req, res) => { try { const company_id = req.user.company_id; // Primeiro, marcar dispositivos como inativos se não receberam heartbeat há mais de 5 minutos await query( `UPDATE devices SET is_active = false WHERE company_id = $1 AND (last_seen IS NULL OR last_seen < NOW() - INTERVAL '5 minutes') AND is_active = true`, [company_id] ); // Agora buscar dispositivos com status atualizado const result = await query( `SELECT d.*, u.name as user_name, u.email as user_email, CASE WHEN d.last_seen IS NULL THEN false WHEN d.last_seen < NOW() - INTERVAL '5 minutes' THEN false ELSE d.is_active END as real_status FROM devices d LEFT JOIN users u ON d.user_id = u.id WHERE d.company_id = $1 ORDER BY d.created_at DESC`, [company_id] ); // Atualizar is_active com o real_status calculado const devices = result.rows.map(device => ({ ...device, is_active: device.real_status, real_status: undefined // Remover campo auxiliar })); res.json({ success: true, devices }); } catch (error) { console.error('Erro ao listar dispositivos:', error); res.status(500).json({ error: 'Erro ao listar dispositivos' }); } }); // ATIVAR DISPOSITIVO (sem auth - usado pelo client) router.post('/activate', async (req, res) => { try { const { activation_key, device_info } = req.body; if (!activation_key) { return res.status(400).json({ error: 'Chave de ativação é obrigatória' }); } // Buscar chave (SEM verificar is_used ou expires_at) const keyResult = await query( 'SELECT * FROM activation_keys WHERE key = $1', [activation_key] ); if (keyResult.rows.length === 0) { return res.status(400).json({ error: 'Chave de ativação inválida' }); } const key = keyResult.rows[0]; const device_id = `DEV-${Date.now()}-${Math.random().toString(36).substring(2, 8).toUpperCase()}`; const device_name = device_info?.device_name || device_info?.hostname || 'Dispositivo'; const hostname = device_info?.hostname || device_name; const username = device_info?.username || ''; // Criar device const deviceResult = await query( `INSERT INTO devices (device_id, device_name, hostname, username, company_id, is_active, created_at) VALUES ($1, $2, $3, $4, $5, true, NOW()) RETURNING *`, [device_id, device_name, hostname, username, key.company_id] ); const device = deviceResult.rows[0]; // Incrementar contador de devices da chave await query( 'UPDATE activation_keys SET devices_count = devices_count + 1 WHERE id = $1', [key.id] ); console.log(`✅ Dispositivo ativado: ${device.device_name} (${device_id})`); res.status(201).json({ success: true, device_id: device.device_id, device_name: device.device_name, company_id: device.company_id, message: 'Dispositivo ativado com sucesso' }); } catch (error) { console.error('Erro ao ativar dispositivo:', error); res.status(500).json({ error: 'Erro ao ativar dispositivo', details: error.message }); } }); // HEARTBEAT (sem auth - usado pelo client) router.post('/heartbeat', async (req, res) => { try { const { device_id } = req.body; if (!device_id) { return res.status(400).json({ error: 'device_id é obrigatório' }); } const result = await query( 'UPDATE devices SET last_seen = NOW(), is_active = true WHERE device_id = $1 RETURNING device_name', [device_id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'Dispositivo não encontrado' }); } console.log(`💓 Heartbeat: ${result.rows[0].device_name}`); res.json({ success: true, message: 'Heartbeat registrado' }); } catch (error) { console.error('Erro heartbeat:', error); res.status(500).json({ error: 'Erro ao registrar heartbeat' }); } }); // ATUALIZAR DISPOSITIVO router.put('/:id', authenticateToken, async (req, res) => { try { const { id } = req.params; const { device_name, user_id, team_id, is_active } = req.body; const company_id = req.user.company_id; console.log(`🔵 PUT /api/devices/${id} - Requisição recebida`); console.log(`🔵 Body recebido:`, JSON.stringify({ device_name, user_id, team_id, is_active }, null, 2)); console.log(`🔵 Company ID:`, company_id); console.log(`🔵 ID recebido (tipo):`, typeof id, id); // Verificar se o dispositivo existe e pertence à company // Aceitar tanto id numérico quanto device_id string let deviceCheck; if (isNaN(id)) { // Se não é número, pode ser device_id deviceCheck = await query( 'SELECT id FROM devices WHERE device_id = $1 AND company_id = $2', [id, company_id] ); } else { // Se é número, é o id numérico deviceCheck = await query( 'SELECT id FROM devices WHERE id = $1 AND company_id = $2', [parseInt(id), company_id] ); } if (deviceCheck.rows.length === 0) { return res.status(404).json({ error: 'Dispositivo não encontrado' }); } const deviceId = deviceCheck.rows[0].id; // Usar o ID numérico real // Se user_id foi fornecido, verificar se o usuário existe e pertence à mesma company if (user_id !== undefined && user_id !== null) { const userCheck = await query( 'SELECT id FROM users WHERE id = $1 AND company_id = $2', [user_id, company_id] ); if (userCheck.rows.length === 0) { return res.status(404).json({ error: 'Usuário não encontrado ou não pertence à sua empresa' }); } } // Construir query dinamicamente baseado nos campos fornecidos const updateFields = []; const updateValues = []; let paramCount = 1; if (device_name !== undefined) { updateFields.push(`device_name = $${paramCount++}`); updateValues.push(device_name); } if (user_id !== undefined) { // Converter string vazia para null, e garantir que seja número ou null let finalUserId = null; if (user_id !== null && user_id !== '' && user_id !== undefined) { finalUserId = parseInt(user_id); if (isNaN(finalUserId)) { return res.status(400).json({ error: 'user_id deve ser um número válido' }); } } updateFields.push(`user_id = $${paramCount++}`); updateValues.push(finalUserId); console.log(`🔵 user_id processado: ${user_id} -> ${finalUserId}`); } if (team_id !== undefined) { updateFields.push(`team_id = $${paramCount++}`); updateValues.push(team_id === null || team_id === '' ? null : team_id); } if (is_active !== undefined) { updateFields.push(`is_active = $${paramCount++}`); updateValues.push(is_active); } if (updateFields.length === 0) { return res.status(400).json({ error: 'Nenhum campo para atualizar' }); } updateValues.push(deviceId, company_id); const queryText = `UPDATE devices SET ${updateFields.join(', ')} WHERE id = $${paramCount++} AND company_id = $${paramCount} RETURNING *, (SELECT name FROM users WHERE id = devices.user_id) as user_name, (SELECT email FROM users WHERE id = devices.user_id) as user_email`; const result = await query(queryText, updateValues); console.log(`✅ Dispositivo ${deviceId} (${id}) atualizado com sucesso`); res.json({ success: true, device: result.rows[0] }); } catch (error) { console.error('Erro ao atualizar dispositivo:', error); console.error('Erro detalhado:', error.message); res.status(500).json({ error: 'Erro ao atualizar dispositivo', details: error.message }); } }); // DELETAR DISPOSITIVO router.delete('/:id', authenticateToken, async (req, res) => { try { const { id } = req.params; const company_id = req.user.company_id; const result = await query( 'DELETE FROM devices WHERE id = $1 AND company_id = $2 RETURNING *', [id, company_id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'Dispositivo não encontrado' }); } res.json({ success: true, message: 'Dispositivo deletado' }); } catch (error) { console.error('Erro ao deletar dispositivo:', error); res.status(500).json({ error: 'Erro ao deletar dispositivo' }); } }); module.exports = router;