/**
 * Recoge las paginas web declaradas por paquetes populares de npm.
 *
 * Pregunta: la web propia que un paquete declara en su package.json, ¿sigue
 * existiendo? Es un enlace que se escribe una vez y que millones de personas ven
 * despues en la ficha del paquete, y nadie lo revisa nunca. Nadie ha publicado
 * esa medicion.
 *
 * Se descartan los enlaces a github.com: son casi todos y golpear un solo
 * dominio miles de veces seria justo lo que este experimento ya aprendio a no
 * hacer. Lo interesante ademas es el sitio propio del proyecto, no su repo.
 *
 *   node tools/npm-homepages.js data/npm-homepages.csv
 */
const fs = require('fs');
const path = require('path');

const OUT = process.argv[2] || path.join(__dirname, '..', 'data', 'npm-homepages.csv');
const HEAD = 'package,downloads_hint,homepage,host\n';
const q = (v) => '"' + String(v == null ? '' : v).replace(/"/g, '""') + '"';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

// Consultas amplias para barrer el registro por temas: la API de busqueda no
// deja pedir "los mas populares" sin texto, asi que se pregunta por areas.
const QUERIES = ['react', 'vue', 'angular', 'node', 'cli', 'test', 'build', 'css',
  'http', 'database', 'aws', 'typescript', 'parser', 'logger', 'auth', 'date',
  'stream', 'json', 'markdown', 'image', 'crypto', 'validation', 'router',
  'webpack', 'eslint', 'graphql', 'websocket', 'queue', 'cache', 'template'];

(async () => {
  fs.mkdirSync(path.dirname(OUT), { recursive: true });
  if (!fs.existsSync(OUT)) fs.writeFileSync(OUT, HEAD);
  const seen = new Set(fs.readFileSync(OUT, 'utf8').split('\n').slice(1)
    .map((l) => (l.match(/^"([^"]*)"/) || [])[1]).filter(Boolean));

  let added = 0;
  for (const term of QUERIES) {
    for (let from = 0; from < 250; from += 250) {
      let j;
      try {
        const r = await fetch(
          `https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(term)}&size=250&from=${from}&popularity=1.0`,
          { headers: { 'User-Agent': 'Mozilla/5.0' } });
        j = await r.json();
      } catch { await sleep(5000); continue; }
      if (!j || !Array.isArray(j.objects)) break;

      const rows = [];
      for (const o of j.objects) {
        const p = o.package || {};
        if (seen.has(p.name)) continue;
        const home = (p.links || {}).homepage || '';
        if (!/^https?:\/\//i.test(home)) continue;
        let host;
        try { host = new URL(home).hostname.replace(/^www\./, ''); } catch { continue; }
        // Fuera repositorios: son el mismo dominio para casi todos.
        if (/^(github\.com|gitlab\.com|bitbucket\.org|codeberg\.org)$/i.test(host)) continue;
        seen.add(p.name);
        rows.push([p.name, (o.score && o.score.detail && o.score.detail.popularity) || '', home, host].map(q).join(','));
      }
      if (rows.length) { fs.appendFileSync(OUT, rows.join('\n') + '\n'); added += rows.length; }
      console.log(`${term} +${rows.length} (total ${added})`);
      await sleep(1200);
    }
  }
  console.log('listo ->', OUT);
})();
