/**
 * Ranking a partir del CSV del barrido de demanda.
 *
 * La medida que importa no es cuantos productos hay (competencia) sino cuantas
 * valoraciones acumulan los que rankean (compradores que ademas volvieron a la
 * ficha). Y el cociente entre ambas: valoraciones por producto listado separa
 * "nicho grande y repartido" de "nicho pequeno donde se vende de verdad".
 *
 *   node tools/demand-report.js data/gumroad-demand.csv [--md]
 */
const fs = require('fs');

function parseCsv(text) {
  const rows = [];
  let row = [], cell = '', q = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i];
    if (q) {
      if (c === '"' && text[i + 1] === '"') { cell += '"'; i++; }
      else if (c === '"') q = false;
      else cell += c;
    } else if (c === '"') q = true;
    else if (c === ',') { row.push(cell); cell = ''; }
    else if (c === '\n') { row.push(cell); rows.push(row); row = []; cell = ''; }
    else if (c !== '\r') cell += c;
  }
  if (cell || row.length) { row.push(cell); rows.push(row); }
  return rows;
}

const rows = parseCsv(fs.readFileSync(process.argv[2], 'utf8')).slice(1).filter((r) => r[0]);
const md = process.argv.includes('--md');

const byTerm = new Map();
for (const [term, total, , name, price, ratings, sales] of rows) {
  if (!byTerm.has(term)) byTerm.set(term, { term, total: +String(total).replace(/,/g, '') || 0, ratings: 0, top: 0, best: 0, bestName: '', prices: [] });
  const t = byTerm.get(term);
  if (!name) continue;
  t.top++;
  t.ratings += +ratings || 0;
  if ((+sales || 0) > t.best) { t.best = +sales; t.bestName = name; }
  if (price) t.prices.push(price);
}

const list = [...byTerm.values()].map((t) => ({
  ...t,
  // Densidad: valoraciones del top 10 por cada 100 productos listados. Alta =
  // pocos vendedores repartiendose compradores reales.
  density: t.total ? (t.ratings / t.total) * 100 : 0,
  freeShare: t.prices.length
    ? t.prices.filter((p) => /^\$?0(\.00)?\+?$/.test(p.trim())).length / t.prices.length : 0,
}));

const fmt = (n, d = 0) => n.toLocaleString('en-GB', { maximumFractionDigits: d });

function table(title, arr) {
  if (md) {
    console.log(`\n### ${title}\n`);
    console.log('| Search term | Products | Ratings in top 10 | Ratings per 100 products | Largest sales count |');
    console.log('|---|---:|---:|---:|---:|');
    arr.forEach((t) => console.log(`| ${t.term} | ${fmt(t.total)} | ${fmt(t.ratings)} | ${fmt(t.density, 1)} | ${t.best ? fmt(t.best) : '-'} |`));
  } else {
    console.log(`\n=== ${title} ===`);
    arr.forEach((t) => console.log(
      `${t.term.padEnd(26)} ${String(fmt(t.total)).padStart(7)} prod · ` +
      `${String(fmt(t.ratings)).padStart(6)} val · ${fmt(t.density, 1).padStart(7)} val/100 · ` +
      `max ventas ${t.best ? fmt(t.best) : '-'}`));
  }
}

console.log(`terminos medidos: ${list.length} · productos consultados: ${rows.filter((r) => r[3]).length}`);
table('Mas valoraciones en el top 10 (donde hay compradores)',
  [...list].sort((a, b) => b.ratings - a.ratings).slice(0, 20));
table('Mejor densidad: valoraciones por cada 100 productos listados',
  [...list].filter((t) => t.total >= 20).sort((a, b) => b.density - a.density).slice(0, 20));
table('Medidos y muertos: top 10 con 5 valoraciones o menos',
  [...list].filter((t) => t.top && t.ratings <= 5).sort((a, b) => b.total - a.total).slice(0, 20));
