// Helpers de formatação pt-BR. Só formatam valores já calculados pelo
// backend Python — nenhuma métrica é derivada aqui.
export function moeda(v) {
return "R$ " + Number(v || 0).toLocaleString("pt-BR", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
export function pct(v) {
return v == null ? "—" : Number(v).toLocaleString("pt-BR", { maximumFractionDigits: 1 }) + "%";
}
export function num(v) {
if (v == null) return "—";
return typeof v === "number" ? v.toLocaleString("pt-BR") : v;
}
export function pipelineVal(o) {
return o.open_pipeline_product_value != null && o.open_pipeline_product_value
? o.open_pipeline_product_value
: o.open_pipeline_amount;
}
export function extrairResumo(md) {
const m = (md || "").split(/##\s+/).find((s) => /resumo executivo/i.test(s.split("\n")[0]));
return m ? m.split("\n").slice(1).join("\n").trim() : "";
}
/** Escapa HTML básico antes de reinjetar como innerHTML. */
export function escapeHtml(s) {
return String(s ?? "")
.replace(/&/g, "&")
.replace(//g, ">");
}
/**
* Converte negrito Markdown (**texto**) e parágrafos em HTML simples.
* Usado só para exibição do resumo já gerado pelo backend — não interpreta
* nem recalcula nada, apenas formata o texto que já veio pronto.
*/
export function renderResumoHtml(texto) {
if (!texto) return "";
const paragrafos = texto
.split(/\n{2,}/)
.map((p) => p.trim())
.filter(Boolean);
return paragrafos
.map((p) => {
const comNegrito = escapeHtml(p)
.replace(/\*\*(.+?)\*\*/g, "$1")
.replace(/\n/g, "
");
return `
${comNegrito}
`; }) .join(""); }