/* =========================================================================
   La Morgue — Reddit Top 100 · content script
   Corre en las páginas de reddit.com. Cuando estás en un hilo (página de
   comentarios), pide el JSON del hilo a la propia sesión de Reddit, calcula
   una puntuación de interacción por comentario (upvotes + respuestas),
   se queda con los 100 con más interacción y exporta la publicación y esos
   comentarios (con sus respuestas anidadas) a un .txt.
   ========================================================================= */

(() => {
  if (window.__redditTop100Loaded) return;
  window.__redditTop100Loaded = true;

  // ---------- Configuración (ajústala a tu gusto) ----------
  const CFG = {
    topN: 100,            // cuántos comentarios exportar
    replyWeight: 10,      // cuánto pesa cada respuesta frente a 1 upvote
    fetchLimit: 500,      // comentarios que pedimos a Reddit (máx. útil ~500)
    sortMode: 'top',      // orden que pedimos: top | confidence | new | controversial
    skipStickied: true,   // ignora comentarios fijados (AutoModerator / avisos de mods)
    maxReplyDepth: 8,     // profundidad máxima de respuestas a volcar en el .txt
  };

  // Resultado del último análisis (para no re-pedir al exportar)
  let lastResult = null;

  // ---------- Detección de página ----------
  function isThreadPage() {
    return /\/comments\/[a-z0-9]+/i.test(location.pathname);
  }

  function getPostId() {
    const parts = location.pathname.split('/').filter(Boolean);
    const idx = parts.indexOf('comments');
    return idx >= 0 && parts[idx + 1] ? parts[idx + 1] : null;
  }

  function threadJsonUrl() {
    const id = getPostId();
    if (!id) return null;
    const params =
      'limit=' + CFG.fetchLimit + '&sort=' + CFG.sortMode + '&raw_json=1';
    // Mismo origen que la pestaña (lleva tus cookies de sesión)
    return location.origin + '/comments/' + id + '.json?' + params;
  }

  // ---------- Métricas de interacción ----------
  // Volumen total de respuestas de una rama (cargadas + colapsadas conocidas)
  function countReplies(node) {
    const replies = node && node.data && node.data.replies;
    if (!replies || !replies.data || !replies.data.children) return 0;
    let total = 0;
    for (const child of replies.data.children) {
      if (child.kind === 't1') {
        total += 1 + countReplies(child);
      } else if (child.kind === 'more') {
        total += (child.data && child.data.count) || 0;
      }
    }
    return total;
  }

  function interactionScore(node) {
    const upvotes = (node.data && node.data.score) || 0;
    const replies = countReplies(node);
    return upvotes + CFG.replyWeight * replies;
  }

  // ---------- Petición y análisis del hilo ----------
  async function fetchThread() {
    const url = threadJsonUrl();
    if (!url) return { ok: false, error: 'no_thread' };

    let res;
    try {
      res = await fetch(url, {
        credentials: 'include',
        headers: { Accept: 'application/json' },
      });
    } catch (e) {
      return { ok: false, error: 'network' };
    }
    if (!res.ok) return { ok: false, error: 'http_' + res.status };

    let json;
    try {
      json = await res.json();
    } catch (e) {
      return { ok: false, error: 'parse' };
    }
    if (!Array.isArray(json) || json.length < 2) {
      return { ok: false, error: 'shape' };
    }

    const postChildren = json[0] && json[0].data && json[0].data.children;
    const post = postChildren && postChildren[0] && postChildren[0].data;
    if (!post) return { ok: false, error: 'shape' };

    const commentChildren =
      (json[1] && json[1].data && json[1].data.children) || [];

    // Separar comentarios reales de los nodos "more" (colapsados)
    let moreTop = 0;
    const tops = [];
    for (const c of commentChildren) {
      if (c.kind === 't1') {
        if (CFG.skipStickied && c.data && c.data.stickied) continue;
        tops.push(c);
      } else if (c.kind === 'more') {
        moreTop += (c.data && c.data.count) || 0;
      }
    }

    // Calcular interacción y ordenar de mayor a menor
    tops.forEach((c) => {
      c.__replies = countReplies(c);
      c.__interaction = interactionScore(c);
    });
    tops.sort((a, b) => b.__interaction - a.__interaction);

    const ranked = tops.slice(0, CFG.topN);

    lastResult = { post, ranked, totalLoaded: tops.length, moreTop };

    return {
      ok: true,
      title: post.title || '(sin título)',
      subreddit: post.subreddit || '',
      numComments: post.num_comments != null ? post.num_comments : null,
      analyzed: tops.length,
      selected: ranked.length,
      topScore: ranked[0] ? ranked[0].data.score : 0,
      preview: ranked.slice(0, 3).map((c) => ({
        author: c.data.author,
        score: c.data.score,
        replies: c.__replies,
      })),
    };
  }

  // ---------- Construcción del .txt ----------
  function fmtDate(utc) {
    return utc ? new Date(utc * 1000).toLocaleString() : '';
  }

  function bodyText(d) {
    let b = d && d.body != null ? d.body : '';
    if (b === '[deleted]') b = '[eliminado por el usuario]';
    if (b === '[removed]') b = '[eliminado por moderación]';
    return b;
  }

  function indentBlock(text, pad) {
    return (text || '')
      .split('\n')
      .map((line) => pad + line)
      .join('\n');
  }

  function renderReplies(node, depth, lines) {
    if (depth > CFG.maxReplyDepth) return;
    const replies = node.data && node.data.replies;
    if (!replies || !replies.data || !replies.data.children) return;

    for (const child of replies.data.children) {
      if (child.kind !== 't1') {
        if (child.kind === 'more' && child.data && child.data.count) {
          const pad = '    '.repeat(depth + 1);
          lines.push(pad + '… (' + child.data.count + ' respuestas más colapsadas)');
        }
        continue;
      }
      const d = child.data;
      const pad = '    '.repeat(depth);
      const op = d.is_submitter ? ' [OP]' : '';
      lines.push('');
      lines.push(pad + '↳ u/' + d.author + op + ' · ' + d.score + ' pts');
      lines.push(indentBlock(bodyText(d), pad + '  '));
      renderReplies(child, depth + 1, lines);
    }
  }

  function buildTxt() {
    if (!lastResult) return null;
    const { post, ranked, totalLoaded, moreTop } = lastResult;
    const L = [];
    const sep = '='.repeat(66);
    const sub = '-'.repeat(66);

    L.push(sep);
    L.push('LA MORGUE · INSTITUTO FORENSE DE MARKETING');
    L.push('EVIDENCIA · PUBLICACIÓN DE REDDIT');
    L.push(sep);
    L.push('Título: ' + (post.title || ''));
    L.push('Autor: u/' + (post.author || '[desconocido]'));
    L.push('Subreddit: r/' + (post.subreddit || ''));
    const ratio =
      post.upvote_ratio != null
        ? Math.round(post.upvote_ratio * 100) + '% positivos'
        : '';
    L.push(
      'Puntuación: ' +
        (post.score != null ? post.score : '?') +
        ' pts' +
        (ratio ? ' (' + ratio + ')' : '')
    );
    L.push(
      'Comentarios totales (según Reddit): ' +
        (post.num_comments != null ? post.num_comments : '?')
    );
    L.push(
      'Comentarios analizados en esta captura: ' +
        totalLoaded +
        (moreTop ? ' (+' + moreTop + ' no cargados)' : '')
    );
    L.push('Fecha: ' + fmtDate(post.created_utc));
    L.push('URL: https://www.reddit.com' + (post.permalink || ''));

    if (post.selftext && post.selftext.trim()) {
      L.push('');
      L.push('Texto de la publicación:');
      L.push(post.selftext.trim());
    }

    L.push('');
    L.push(sep);
    L.push('TOP ' + ranked.length + ' COMENTARIOS POR INTERACCIÓN');
    L.push('(interacción = upvotes + ' + CFG.replyWeight + ' × respuestas)');
    L.push(sep);
    L.push('');

    ranked.forEach((c, i) => {
      const d = c.data;
      const op = d.is_submitter ? ' [OP]' : '';
      L.push(
        '#' + (i + 1) +
          '  u/' + d.author + op +
          '  ·  ' + d.score + ' pts' +
          '  ·  ' + c.__replies + ' respuestas' +
          '  ·  interacción ' + c.__interaction
      );
      L.push(bodyText(d));

      const replyLines = [];
      renderReplies(c, 1, replyLines);
      if (replyLines.length) L.push(...replyLines);

      L.push('');
      L.push(sub);
      L.push('');
    });

    return L.join('\n');
  }

  function safeName(title) {
    const base = (title || 'hilo')
      .replace(/[^\w\sáéíóúñÁÉÍÓÚÑ-]/gi, '')
      .trim()
      .replace(/\s+/g, '_')
      .slice(0, 50);
    return 'reddit_top100_' + (base || 'hilo') + '.txt';
  }

  function download() {
    const txt = buildTxt();
    if (!txt) return { ok: false, error: 'no_data' };
    const blob = new Blob([txt], { type: 'text/plain;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = safeName(lastResult.post && lastResult.post.title);
    document.body.appendChild(a);
    a.click();
    a.remove();
    setTimeout(() => URL.revokeObjectURL(url), 1500);
    return { ok: true, count: lastResult.ranked.length };
  }

  // ---------- Mensajería con el popup ----------
  chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
    (async () => {
      switch (msg && msg.type) {
        case 'PING':
          sendResponse({ ok: true, isThread: isThreadPage() });
          break;
        case 'ANALYZE':
          if (!isThreadPage()) {
            sendResponse({ ok: false, error: 'no_thread' });
            break;
          }
          sendResponse(await fetchThread());
          break;
        case 'EXPORT':
          if (!lastResult) {
            if (!isThreadPage()) {
              sendResponse({ ok: false, error: 'no_thread' });
              break;
            }
            const r = await fetchThread();
            if (!r.ok) {
              sendResponse(r);
              break;
            }
          }
          sendResponse(download());
          break;
        default:
          sendResponse({ ok: false, error: 'unknown' });
      }
    })();
    return true; // respuesta asíncrona
  });
})();
