/**
 * PDF Text Extractor — Wrapper para pdf.js (pdfjs-dist).
 *
 * Substitui pdfplumber do backend Python.
 * Usa pdf.js para extrair texto de ArrayBuffer de PDF.
 *
 * Dependencia: ../lib/pdf.min.mjs e ../lib/pdf.worker.min.mjs
 */

// Importar pdf.js (ESM build)
// O path e relativo ao modulo que importa este arquivo
let pdfjsLib = null;

/**
 * Inicializa pdf.js carregando a lib e configurando o worker.
 * Chamado automaticamente na primeira extracao.
 */
async function initPdfJs() {
  if (pdfjsLib) return;

  try {
    // Tentar import ESM
    pdfjsLib = await import(chrome.runtime.getURL("lib/pdf.min.mjs"));
  } catch {
    // Fallback: pode estar como global (se carregado via <script>)
    if (typeof globalThis.pdfjsLib !== "undefined") {
      pdfjsLib = globalThis.pdfjsLib;
    } else {
      throw new Error(
        "pdf.js nao encontrado. Verifique se lib/pdf.min.mjs esta presente na extensao."
      );
    }
  }

  // Configurar worker
  const workerUrl = chrome.runtime.getURL("lib/pdf.worker.min.mjs");
  pdfjsLib.GlobalWorkerOptions.workerSrc = workerUrl;
}

/**
 * Extrai texto de um PDF a partir de ArrayBuffer.
 *
 * @param {ArrayBuffer} pdfBytes — Conteudo do PDF
 * @param {object} [options]
 * @param {function} [options.onProgress] — Callback(pageNum, totalPages) para progresso
 * @param {boolean} [options.preserveLayout=false] — Tentar preservar layout espacial
 * @returns {Promise<{content:string, pageCount:number, tokenCount:number}>}
 */
export async function extractText(pdfBytes, options = {}) {
  const { onProgress, preserveLayout = false } = options;

  await initPdfJs();

  const loadingTask = pdfjsLib.getDocument({
    data: new Uint8Array(pdfBytes),
    useSystemFonts: true,
    standardFontDataUrl: chrome.runtime.getURL("lib/standard_fonts/"),
    cMapUrl: chrome.runtime.getURL("lib/cmaps/"),
    cMapPacked: true,
  });

  const pdf = await loadingTask.promise;
  const pageCount = pdf.numPages;
  const textParts = [];

  for (let i = 1; i <= pageCount; i++) {
    try {
      const page = await pdf.getPage(i);
      const textContent = await page.getTextContent();

      let pageText;
      if (preserveLayout) {
        pageText = layoutAwareText(textContent);
      } else {
        pageText = textContent.items
          .filter(item => item.str !== undefined)
          .map(item => item.str)
          .join(" ")
          .replace(/\s+/g, " ")
          .trim();
      }

      if (pageText) textParts.push(pageText);

      if (onProgress) onProgress(i, pageCount);
    } catch (e) {
      console.warn(`[pdf-extractor] Erro na pagina ${i}:`, e);
      // Continuar com proximas paginas
    }
  }

  const content = textParts.join("\n\n");
  const tokenCount = Math.floor(content.length / 4);

  if (!content.trim()) {
    throw new Error("PDF sem texto extraivel (pode ser imagem escaneada).");
  }

  return { content, pageCount, tokenCount };
}

/**
 * Extrai texto preservando layout espacial (posicoes Y agrupam linhas).
 * Mais preciso para documentos juridicos com colunas/formatacao.
 * @param {object} textContent — Resultado de page.getTextContent()
 * @returns {string}
 */
function layoutAwareText(textContent) {
  const items = textContent.items.filter(item => item.str !== undefined);
  if (!items.length) return "";

  // Agrupar por posicao Y (com tolerancia de 2px)
  const lines = [];
  let currentLine = [];
  let lastY = null;
  const Y_TOLERANCE = 2;

  // Ordenar por Y (descendente, como PDF coordenadas) e depois X
  const sorted = [...items].sort((a, b) => {
    const yDiff = b.transform[5] - a.transform[5]; // Y descendente
    if (Math.abs(yDiff) > Y_TOLERANCE) return yDiff;
    return a.transform[4] - b.transform[4]; // X ascendente
  });

  for (const item of sorted) {
    const y = item.transform[5];
    if (lastY !== null && Math.abs(y - lastY) > Y_TOLERANCE) {
      if (currentLine.length) lines.push(currentLine);
      currentLine = [];
    }
    currentLine.push(item);
    lastY = y;
  }
  if (currentLine.length) lines.push(currentLine);

  // Montar texto por linha
  return lines
    .map(line => {
      // Ordenar itens na linha por X
      line.sort((a, b) => a.transform[4] - b.transform[4]);

      let lineText = "";
      let lastX = 0;
      for (const item of line) {
        const x = item.transform[4];
        // Inserir espaco se houver gap significativo
        if (lineText && (x - lastX) > 5) {
          lineText += " ";
        }
        lineText += item.str;
        lastX = x + (item.width || item.str.length * 5);
      }
      return lineText.trim();
    })
    .filter(l => l)
    .join("\n");
}

/**
 * Extrai texto e retorna no formato esperado pelo CearIA (compativel com load-context).
 *
 * @param {ArrayBuffer} pdfBytes
 * @param {string} numeroPasta — Numero da pasta para nome amigavel
 * @param {function} [onProgress]
 * @returns {Promise<{content:string, fileName:string, pageCount:number, tokenCount:number, numeroPasta:string}>}
 */
export async function extractForContext(pdfBytes, numeroPasta = "", onProgress = null) {
  const { content, pageCount, tokenCount } = await extractText(pdfBytes, { onProgress });

  const fileName = numeroPasta
    ? `Pasta ${numeroPasta} (${pageCount} pags).pdf`
    : `Documento (${pageCount} pags).pdf`;

  return {
    content,
    fileName,
    pageCount,
    tokenCount,
    numeroPasta,
  };
}
