const { consultarViabilidade, discoverDataType } = require('../service/viabilidadeService'); const { processCsvFile, countValidLines } = require('../service/csvService'); const { getJob, createJob } = require('../service/jobStore.service'); const fs = require('fs'); const path = require('path'); // Controlador para consultar viabilidade async function consultarViabilidadeController(req, res) { try { const data = req.body; data.source = 'viabiliza.sothis.com.br'; const result = await consultarViabilidade(data); res.json(result); } catch (error) { console.error("Erro ao consultar viabilidade:", error && (error.message || error)); res.status(500).json({ error: "Erro ao consultar viabilidade" }); } } // Controlador para consultar viabilidade via geolocalização async function consultarViaGeolocalizacaoController(req, res) { try { const data = req.body; data.source = 'viabiliza.sothis.com.br'; const result = await consultarViabilidade(data); res.json(result); } catch (error) { console.error("Erro ao consultar viabilidade por geolocalização:", error && (error.message || error)); res.status(500).json({ error: "Erro ao consultar viabilidade por geolocalização" }); } } async function uploadCsvFile(req, res) { try { // validação simples: verifica se multer populou req.file if (!req.file) { return res.status(400).json({ error: 'Nenhum arquivo enviado. Campo do form deve ser "csvfile".' }); } const filePath = req.file.path; const originalName = req.file.originalname || req.file.filename || 'input.csv'; // Verifica o tipo de dados do CSV const dataType = await discoverDataType(filePath); if (dataType === 'unknown') { return res.status(400).json({ error: 'Formato de CSV inválido. Deve conter colunas CEP e Número ou Latitude e Longitude.' }); } // Conta as linhas válidas primeiro const total = await countValidLines(filePath); if (total === 0) { return res.status(400).json({ error: 'Nenhuma linha válida encontrada no CSV. Verifique se há colunas CEP e Número.' }); } // Cria o job const jobId = createJob(total); // Inicia o processamento em background (não aguarda) processCsvFile(jobId, filePath, originalName).catch(err => { console.error('Erro no processamento em background:', err); // Em caso de erro, marca o job como falhado require('../service/jobStore.service').failJob(jobId, err.message); }); // Retorna o jobId imediatamente para acompanhamento em tempo real return res.json({ jobId }); } catch (error) { console.error("Erro ao iniciar processamento do CSV:", error && (error.message || error)); return res.status(500).json({ error: 'Erro ao iniciar processamento do CSV' }); } } async function getJobController(req, res) { try { const jobId = req.params.jobId; const job = getJob(jobId); if (!job) { return res.status(404).json({ error: 'Job não encontrado' }); } res.json(job); } catch (error) { console.error("Erro ao obter job:", error && (error.message || error)); return res.status(500).json({ error: 'Erro ao obter job' }); } } // Controlador para download do CSV processado // Verifica se o job está concluído e serve o arquivo para download async function downloadCsvController(req, res) { try { const jobId = req.params.jobId; const job = getJob(jobId); // Verifica se o job existe, está concluído e tem um link de download if (!job) { return res.status(404).json({ error: 'Job não encontrado' }); } if (job.status !== 'done') { return res.status(400).json({ error: 'Processamento ainda não concluído' }); } if (!job.download) { return res.status(404).json({ error: 'Arquivo de download não disponível' }); } // Extrai o nome do arquivo do campo download (ex: '/download/processed_123.csv' -> 'processed_123.csv') const filename = path.basename(job.download); const filePath = path.join(__dirname, '..', 'outputs', filename); // Verifica se o arquivo existe no sistema de arquivos if (!fs.existsSync(filePath)) { return res.status(404).json({ error: 'Arquivo não encontrado no servidor' }); } // Inicia o download do arquivo res.download(filePath, filename, (err) => { if (err) { console.error("Erro ao fazer download do arquivo:", err); // Se o download falhar, envia erro (mas headers já podem ter sido enviados) if (!res.headersSent) { res.status(500).json({ error: 'Erro ao fazer download do arquivo' }); } } }); } catch (error) { console.error("Erro no controlador de download:", error && (error.message || error)); if (!res.headersSent) { res.status(500).json({ error: 'Erro interno no servidor' }); } } } // Controlador para download dos modelos de CSV // Aceita parâmetro :type ('cep' ou 'geo') para escolher qual modelo baixar async function downloadModelController(req, res) { try { const type = req.params.type; let filename; // Define o nome do arquivo baseado no tipo if (type === 'cep') { filename = 'modelo.viabilidade-cep.csv'; } else if (type === 'geo') { filename = 'modelo.viabilidade-geolocalizacao.csv'; } else { return res.status(400).json({ error: 'Tipo de modelo inválido. Use "cep" ou "geo".' }); } const filePath = path.join(__dirname, '..', 'models', filename); // Verifica se o arquivo existe if (!fs.existsSync(filePath)) { return res.status(404).json({ error: 'Arquivo de modelo não encontrado' }); } // Inicia o download do arquivo res.download(filePath, filename, (err) => { if (err) { console.error("Erro ao fazer download do modelo:", err); if (!res.headersSent) { res.status(500).json({ error: 'Erro ao fazer download do modelo' }); } } }); } catch (error) { console.error("Erro no controlador de download de modelo:", error && (error.message || error)); if (!res.headersSent) { res.status(500).json({ error: 'Erro interno no servidor' }); } } } module.exports = { consultarViabilidadeController, uploadCsvFile, getJobController, downloadCsvController, downloadModelController, consultarViaGeolocalizacaoController };