const axios = require('axios'); const fs = require('fs'); const readline = require('readline'); const path = require('path'); const XLSX = require('xlsx'); const { apiConfig, apiViabilidadeUrl, apiUrlBase } = require('../config/apiConfig'); function normalizeHeader(value) { return String(value || '') .trim() .toLowerCase() .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .replace(/[_-]+/g, ' ') .replace(/\s+/g, ' '); } function hasHeader(headers, aliases) { const normalizedAliases = aliases.map(normalizeHeader); return headers.some(header => normalizedAliases.includes(header)); } function isExcelFile(filePath) { const ext = path.extname(filePath).toLowerCase(); if (['.xls', '.xlsx'].includes(ext)) return true; const fileStart = fs.readFileSync(filePath).subarray(0, 512); const signature = fileStart.subarray(0, 8); const isZipBasedXlsx = signature[0] === 0x50 && signature[1] === 0x4b; const isOleBasedXls = signature[0] === 0xd0 && signature[1] === 0xcf && signature[2] === 0x11 && signature[3] === 0xe0 && signature[4] === 0xa1 && signature[5] === 0xb1 && signature[6] === 0x1a && signature[7] === 0xe1; const startText = fileStart.toString('latin1').trimStart().toLowerCase(); const isHtmlExcel = startText.startsWith(' ({ delimiter, count: line.split(delimiter).length })) .sort((a, b) => b.count - a.count)[0].delimiter; } function findHeaderRow(rows) { return rows.find(row => { const headers = row.map(normalizeHeader); const hasCepNumero = hasCepHeader(headers) && hasAddressOrNumberHeader(headers); const hasGeo = hasGeoHeaders(headers); return hasCepNumero || hasGeo; }) || []; } function readExcelHeaders(filePath) { const workbook = XLSX.readFile(filePath, { cellDates: false, raw: false }); const firstSheetName = workbook.SheetNames[0]; if (!firstSheetName) return []; const rows = XLSX.utils.sheet_to_json(workbook.Sheets[firstSheetName], { header: 1, blankrows: true, defval: '' }); return findHeaderRow(rows).map(normalizeHeader); } async function readDelimitedHeaders(filePath) { const instream = fs.createReadStream(filePath, { encoding: 'utf8' }); const rl = readline.createInterface({ input: instream, crlfDelay: Infinity }); for await (const rawLine of rl) { const line = rawLine.replace(/^\uFEFF/, '').replace(/\r$/, ''); if (!line.trim()) continue; const headers = line.split(detectDelimiter(line)).map(normalizeHeader); const hasCepNumero = hasCepHeader(headers) && hasAddressOrNumberHeader(headers); const hasGeo = hasGeoHeaders(headers); if (hasCepNumero || hasGeo) { rl.close(); return headers; } } rl.close(); return []; } function hasCepHeader(headers) { return headers.some(header => /\bcep\b/.test(header) || header === 'codigo postal'); } function hasAddressOrNumberHeader(headers) { return headers.some(header => ['numero', 'num', 'nº', 'n°'].includes(header) || header.includes('endereco') || header.includes('logradouro')); } function hasGeoHeaders(headers) { return hasHeader(headers, ['latitude', 'lat']) && hasHeader(headers, ['longitude', 'long', 'lng', 'lon']); } async function consultarViabilidade(data) { try { const dataType = await discoverDataType(data); let endpoint = apiUrlBase; if (dataType === 'geolocalizacao') { endpoint += 'viabilidade/lat-long'; } else { endpoint += 'viabilidade'; } const response = await axios.post(endpoint, data, { timeout: 10000, headers: { 'Content-Type': 'application/json' } }); console.log('Resposta da API de viabilidade:', response.data); return (response.data); } catch (error) { throw error; } } // Preciso de uma função para verificar se os dados vindos são de CEP ou de geolocalização async function discoverDataType(input) { if (typeof input === 'string') { const headers = isExcelFile(input) ? readExcelHeaders(input) : await readDelimitedHeaders(input); const hasCepNumero = hasCepHeader(headers) && hasAddressOrNumberHeader(headers); if (hasCepNumero) { return 'cep'; } else if (hasGeoHeaders(headers)) { return 'geolocalizacao'; } else { return 'unknown'; } } else if (typeof input === 'object') { // Trata como objeto de dados if (input.cep && input.numero) { return 'cep'; } else if (input.latitude !== undefined && input.longitude !== undefined) { return 'geolocalizacao'; } else { return 'unknown'; } } else { return 'unknown'; } } module.exports = { consultarViabilidade, discoverDataType };