/* ============================================================
   CAPA DE DATOS — Panel de Campañas Meta Ads
   Colectivo Inmobiliario · PRODUCCIÓN
   ------------------------------------------------------------
   Transforma la respuesta de api.php (Meta Marketing API)
   en los objetos globales que consumen views.jsx / app.jsx.
   ============================================================ */

const TIPO_ACCENT = {
  residential: "var(--accent-residential)",
  commercial:  "var(--accent-commercial)",
  rental:      "var(--accent-rental)",
  land:        "var(--accent-land)",
  coastal:     "var(--accent-coastal)",
  new:         "var(--accent-new)",
};

const TIPO_LABEL = {
  residential: "Residencial",
  commercial:  "Comercial",
  rental:      "Renta",
  land:        "Terreno",
  coastal:     "Costa",
  new:         "Preventa",
};

// ----- MÉTRICAS DERIVADAS ------------------------------------
function deriva(m) {
  const leads = m.leads || 0;
  const clics = m.clics || 0;
  const imp   = m.impresiones || 0;
  const alc   = m.alcance || 0;
  const gasto = m.gasto || 0;
  const pres  = m.presupuesto || 0;
  return {
    ...m,
    cpl:       leads ? gasto / leads : null,
    ctr:       imp   ? clics / imp   : 0,
    cpc:       clics ? gasto / clics : 0,
    cpm:       imp   ? (gasto / imp) * 1000 : 0,
    frecuencia: alc  ? imp / alc     : 0,
    ritmo:     pres  ? gasto / pres  : 0,
  };
}

function sumaCrudos(rows) {
  return rows.reduce(
    (a, r) => ({
      presupuesto: a.presupuesto + (r.presupuesto || 0),
      gasto:       a.gasto       + (r.gasto       || 0),
      impresiones: a.impresiones + (r.impresiones || 0),
      alcance:     a.alcance     + (r.alcance     || 0),
      clics:       a.clics       + (r.clics       || 0),
      leads:       a.leads       + (r.leads       || 0),
    }),
    { presupuesto: 0, gasto: 0, impresiones: 0, alcance: 0, clics: 0, leads: 0 }
  );
}

// ----- SEMÁFORO (CPL en MXN) ----------------------------------
// Verde < $100 · Amarillo $100–$250 · Rojo > $250
function salud(cpl) {
  if (cpl == null) return { level: "none",  color: "var(--mist)",    label: "Sin leads", token: "none" };
  if (cpl < 100)   return { level: "ok",    color: "var(--success)", label: "Saludable", token: "ok"   };
  if (cpl <= 250)  return { level: "warn",  color: "var(--warning)", label: "Atención",  token: "warn" };
  return             { level: "bad",    color: "var(--danger)",  label: "Crítico",   token: "bad"  };
}

// ----- FORMATEADORES (es-MX) ----------------------------------
const nf0 = new Intl.NumberFormat("es-MX", { maximumFractionDigits: 0 });
const nf1 = new Intl.NumberFormat("es-MX", { minimumFractionDigits: 1, maximumFractionDigits: 1 });
const nf2 = new Intl.NumberFormat("es-MX", { minimumFractionDigits: 2, maximumFractionDigits: 2 });

const fmt = {
  mxn:     (v) => "$" + nf0.format(Math.round(v || 0)),
  mxnFull: (v) => "$" + nf0.format(Math.round(v || 0)) + " MXN",
  mxn2:    (v) => "$" + nf2.format(v || 0),
  int:     (v) => nf0.format(Math.round(v || 0)),
  compact: (v) => {
    if (v >= 1000000) return nf1.format(v / 1000000) + "M";
    if (v >= 1000)    return nf0.format(v / 1000) + "K";
    return nf0.format(v || 0);
  },
  pct:   (v) => nf2.format((v || 0) * 100) + "%",
  pct0:  (v) => nf0.format((v || 0) * 100) + "%",
  freq:  (v) => nf2.format(v || 0) + "×",
  fecha: (iso) => {
    if (!iso) return "";
    const [y, m, d] = iso.split("-");
    const meses = ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"];
    return `${parseInt(d, 10)} ${meses[parseInt(m, 10) - 1]}`;
  },
  reloj: (date) => {
    const meses = ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"];
    const hh = String(date.getHours()).padStart(2, "0");
    const mm = String(date.getMinutes()).padStart(2, "0");
    return `${date.getDate()} ${meses[date.getMonth()]} ${date.getFullYear()}, ${hh}:${mm}`;
  },
};

// ----- TRANSFORMAR RESPUESTA DE API.PHP ----------------------
function processAPIData(raw) {
  // Seleccionar cuenta Colectivo Inmobiliario si existe, sino la primera
  const account = raw.accounts?.find(a => /colectivo/i.test(a.name)) || raw.accounts?.[0];
  if (!account) throw new Error("No se encontraron cuentas publicitarias.");

  const rawAdsets = account.adsets || [];

  // Construir ADSETS con métricas derivadas
  const ADSETS = rawAdsets.map(a => deriva({
    id:          a.id,
    campaña:     a.campaña,
    nombre:      a.nombre,
    estado:      a.estado,
    presupuesto: a.presupuesto || 0,
    gasto:       a.gasto       || 0,
    impresiones: a.impresiones || 0,
    alcance:     a.alcance     || 0,
    clics:       a.clics       || 0,
    leads:       a.leads       || 0,
  }));

  // Construir CAMPAIGNS con rollup de adsets
  const CAMPAIGNS = (account.campaigns || []).map(c => {
    const sets     = ADSETS.filter(a => a.campaña === c.id);
    const rollup   = sets.length > 0 ? sumaCrudos(sets) : {
      presupuesto: c.presupuesto || 0,
      gasto:       c.gasto       || 0,
      impresiones: c.impresiones || 0,
      alcance:     c.alcance     || 0,
      clics:       c.clics       || 0,
      leads:       c.leads       || 0,
    };
    return {
      ...deriva(rollup),
      id:        c.id,
      nombre:    c.nombre,
      proyecto:  c.nombre.split('|')[0].trim(),
      tipo:      c.tipo || 'residential',
      estado:    c.estado,
      accent:    TIPO_ACCENT[c.tipo] || TIPO_ACCENT.residential,
      tipoLabel: TIPO_LABEL[c.tipo]  || TIPO_LABEL.residential,
      nConjuntos: sets.length || c.nConjuntos || 0,
    };
  });

  // Construir SERIES diarias por campaña y agregada
  const dailyData = account.daily || [];
  const SERIES = {};
  CAMPAIGNS.forEach(c => {
    if (dailyData.length === 0) {
      SERIES[c.id] = [];
    } else {
      // Para campañas individuales, repartir la serie total proporcional al gasto
      const campShare = CAMPAIGNS.reduce((t, x) => t + (x.gasto || 0), 0);
      const ratio = campShare > 0 ? (c.gasto || 0) / campShare : 1 / CAMPAIGNS.length;
      SERIES[c.id] = dailyData.map(d => ({
        fecha: d.fecha,
        gasto: Math.round((d.gasto || 0) * ratio),
        leads: Math.round((d.leads || 0) * ratio),
        cpl:   (d.leads || 0) > 0 ? Math.round(((d.gasto || 0) * ratio) / Math.round((d.leads || 0) * ratio)) : null,
      }));
    }
  });

  const SERIES_TODAS = dailyData.map(d => ({
    fecha: d.fecha,
    gasto: d.gasto || 0,
    leads: d.leads || 0,
    cpl:   (d.leads || 0) > 0 ? d.cpl : null,
  }));

  // DELTA_FACTORS: comparar últimos 7 días vs 7 anteriores
  const DELTA_FACTORS = calcDeltaFactors(dailyData);

  // totalesDe: suma de campañas por id
  function totalesDe(campaignIds) {
    const cs = CAMPAIGNS.filter(c => campaignIds.includes(c.id));
    return deriva(sumaCrudos(cs));
  }

  return { CAMPAIGNS, ADSETS, SERIES, SERIES_TODAS, totalesDe, salud, fmt, DELTA_FACTORS, TIPO_ACCENT, TIPO_LABEL };
}

function calcDeltaFactors(daily) {
  if (daily.length < 14) return { gasto: 1, leads: 1, cpl: 1, alcance: 1 };
  const recent = daily.slice(-7);
  const prev   = daily.slice(-14, -7);
  const sum = (arr, k) => arr.reduce((t, d) => t + (d[k] || 0), 0);
  const rG = sum(recent, 'gasto'), pG = sum(prev, 'gasto');
  const rL = sum(recent, 'leads'), pL = sum(prev, 'leads');
  return {
    gasto:  pG > 0 ? rG / pG : 1,
    leads:  pL > 0 ? rL / pL : 1,
    cpl:    (pL > 0 && rL > 0) ? (rG / rL) / (pG / pL) : 1,
    alcance: 1,
  };
}

// Exponer utilidades (los globals de CAMPAIGNS etc. se asignan en app.jsx)
Object.assign(window, { salud, fmt, TIPO_ACCENT, TIPO_LABEL, processAPIData, sumaCrudos, deriva });
