const dotenv = require("dotenv"); dotenv.config(); const express = require("express"); const path = require("path"); const cors = require("cors"); const { fetchJson } = require("./services/jsonService"); const { getMinDistance } = require("./services/distanceService"); const { geocodeWithGoogle } = require("./services/geocodeService"); const { insertConsultaData } = require("./models/databaseModel"); function createApp() { const app = express(); app.use(cors()); app.use(express.static(path.join(__dirname, "public"))); app.use(express.json()); // manual CEP+Numero query: resolves ViaCEP -> Nominatim -> Geogrid app.get("/consulta-cep", async (req, res) => { const { cep: rawCep, numero: rawNumero } = req.query; if (!rawCep) return res.status(400).json({ error: "cep é obrigatório" }); const cep = String(rawCep).trim().replace(/\D/g, ""); if (cep.length !== 8) return res.status(400).json({ error: "cep inválido, verifique se foram digitados apenas números" }); const numero = rawNumero ? String(rawNumero).trim() : ""; try { const viaCepUrl = `https://viacep.com.br/ws/${cep}/json/`; let viaCepData = await fetchJson(viaCepUrl); // ViaCEP com retry e backoff (corrige shadowing e trata exceções) const maxAttempts = 5; let attempt = 0; let retryDelayMs = 1000; // delay inicial if (!viaCepData || viaCepData.erro) { while (attempt < maxAttempts) { try { viaCepData = await fetchJson(viaCepUrl); if (viaCepData && !viaCepData.erro) break; console.info(`[INFO] ViaCEP retornou erro ou vazio na tentativa ${attempt + 1} para CEP ${cep}`); } catch (e) { console.warn(`[WARN] Erro na chamada ViaCEP (tentativa ${attempt + 1}) para ${cep}: ${e && e.message ? e.message : e}`); } attempt++; console.info(`[INFO] Aguardando ${retryDelayMs}ms antes da próxima tentativa ViaCEP (${attempt}/${maxAttempts})`); await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); retryDelayMs *= 2; } } if (!viaCepData || viaCepData.erro) { console.error(`[ERROR] ViaCEP falhou após ${maxAttempts} tentativas para CEP ${cep}`); return res.status(404).json({ error: "CEP não encontrado" }); } const logradouro = viaCepData.logradouro || ""; const bairro = viaCepData.bairro || ""; const cidade = viaCepData.localidade || ""; const uf = viaCepData.uf || ""; const endereco = `${logradouro}, ${numero}, ${bairro}, ${cidade} - ${uf}` .replace(/, ,/g, ",") .replace(/^,\s*/, ""); if (!process.env.GOOGLE_API_KEY) return res .status(500) .json({ error: "GOOGLE_API_KEY não definida no servidor" }); const geo = await geocodeWithGoogle(endereco || `${cidade} ${uf} ${cep}`); if (!geo) return res .status(404) .json({ error: "geocode não encontrado (Google)" }); const lat = Number(geo.lat); const lon = Number(geo.lon); const result = await getMinDistance(lat, lon); // determinar valores de retorno padrão let distancia = null; let dedicado = "Não viável"; let naoDedicado = "Não viável"; if (result && result.dist !== undefined && result.dist !== null) { distancia = result.dist; // preciso criar 2 campos: Link Dedicado e Link Não Dedicado em que o dedicado é viável até 1000m e o não dedicado até 500m if (distancia <= 500) { dedicado = "Viável"; naoDedicado = "Viável"; } else if (distancia <= 1000) { dedicado = "Viável"; naoDedicado = "Não viável"; } else { dedicado = "Não viável"; naoDedicado = "Não viável"; } } else { dedicado = "Não viável"; naoDedicado = "Não viável"; } const response = { endereco, latitude: lat, longitude: lon, distancia, dedicado, naoDedicado, }; // Inserção no banco: usar fire-and-forget para não atrasar a resposta ao usuário. // Se preferir garantir que a gravação ocorreu antes de responder, troque a chamada abaixo por: // await insertConsultaData(cep, uf, cidade, bairro, logradouro); insertConsultaData(cep, uf, cidade, bairro, logradouro, dedicado, naoDedicado) .then(() => console.info(`[INFO] Consulta salva para CEP ${cep}`)) .catch((err) => console.error(`[ERROR] Falha ao salvar consulta para CEP ${cep}:`, err)); return res.json(response); } catch (err) { console.error(err); return res.status(500).json({ error: "erro na consulta" }); } }); return app; } module.exports = createApp;