/**
 * DOCX Generator — Geracao de DOCX no browser via lib docx.
 *
 * Substitui o backend Python (docx_formatter.py) SEM classificacao semantica OpenAI.
 * Usa a lib "docx" (npm: docx) para gerar DOCX formatado no padrao Procuradoria.
 *
 * Margens: 3.5cm (top), 2.5cm (bottom), 3cm (left), 3cm (right)
 * Fonte: Segoe UI 12pt
 * Estilos: headings em negrito, citacoes com recuo, paragrafos com recuo primeira linha.
 *
 * Dependencia: ../lib/docx.min.js (UMD bundle)
 */

let docxLib = null;

/**
 * Inicializa a lib docx carregando o UMD bundle.
 */
async function initDocx() {
  if (docxLib) return;

  // O docx.min.js (UMD) expoe como global "docx" quando carregado via importScripts ou <script>
  // Em ES module context, tentamos import dinamico
  try {
    // Se ja esta como global (carregado via <script> no HTML)
    if (typeof globalThis.docx !== "undefined") {
      docxLib = globalThis.docx;
      return;
    }

    // Tentar carregar via importScripts (funciona em service worker)
    if (typeof importScripts === "function") {
      importScripts(chrome.runtime.getURL("lib/docx.min.js"));
      docxLib = globalThis.docx;
      return;
    }

    // Fallback: criar script tag dinamicamente
    await new Promise((resolve, reject) => {
      const script = document.createElement("script");
      script.src = chrome.runtime.getURL("lib/docx.min.js");
      script.onload = () => {
        docxLib = globalThis.docx;
        resolve();
      };
      script.onerror = () => reject(new Error("Falha ao carregar docx.min.js"));
      document.head.appendChild(script);
    });
  } catch (e) {
    throw new Error(`docx lib nao encontrada: ${e.message}`);
  }
}

// ── Constantes de formatacao (padrao Procuradoria PGE-PE) ───────────────

const FONT = "Segoe UI";
const FONT_SIZE = 24; // half-points (12pt = 24 half-points)
const FONT_SIZE_SMALL = 20; // 10pt para rodape
const LINE_SPACING = 360; // 1.5 line spacing (em twips: 240 * 1.5)

// Margens em twips (1cm = 567 twips)
const MARGIN_TOP = 1985;    // 3.5cm
const MARGIN_BOTTOM = 1418; // 2.5cm
const MARGIN_LEFT = 1701;   // 3cm
const MARGIN_RIGHT = 1701;  // 3cm

// Recuo primeira linha em twips
const FIRST_LINE_INDENT = 1134; // ~2cm

// Recuo blockquote em twips
const BLOCKQUOTE_INDENT = 1701; // 3cm

/**
 * Converte markdown para DOCX bytes (ArrayBuffer).
 * Usa parsing simples sem classificacao semantica.
 *
 * @param {string} markdown — Texto markdown da minuta
 * @param {object} [options]
 * @param {string} [options.title=""] — Titulo do documento (opcional, para propriedades)
 * @returns {Promise<ArrayBuffer>} DOCX como ArrayBuffer
 */
export async function markdownToDocx(markdown, options = {}) {
  await initDocx();

  const { Document, Paragraph, TextRun, HeadingLevel, AlignmentType, Packer, Header, Footer, PageNumber } = docxLib;

  const { title = "" } = options;

  // Limpar markdown
  const cleaned = stripHeaderFooter(markdown);
  const blocks = parseMarkdown(cleaned);

  // Converter blocos para paragrafos docx
  const paragraphs = [];

  for (const block of blocks) {
    switch (block.type) {
      case "heading1":
        paragraphs.push(new Paragraph({
          children: [new TextRun({ text: block.text, bold: true, font: FONT, size: 28 })], // 14pt
          heading: HeadingLevel.HEADING_1,
          alignment: AlignmentType.CENTER,
          spacing: { before: 240, after: 120, line: LINE_SPACING },
        }));
        break;

      case "heading2":
        paragraphs.push(new Paragraph({
          children: [new TextRun({ text: block.text, bold: true, font: FONT, size: FONT_SIZE })],
          heading: HeadingLevel.HEADING_2,
          spacing: { before: 200, after: 100, line: LINE_SPACING },
        }));
        break;

      case "heading3":
        paragraphs.push(new Paragraph({
          children: [new TextRun({ text: block.text, bold: true, font: FONT, size: FONT_SIZE })],
          heading: HeadingLevel.HEADING_3,
          spacing: { before: 160, after: 80, line: LINE_SPACING },
        }));
        break;

      case "blockquote":
        paragraphs.push(new Paragraph({
          children: parseInlineFormatting(block.text, { font: FONT, size: FONT_SIZE, italics: true }),
          indent: { left: BLOCKQUOTE_INDENT, right: BLOCKQUOTE_INDENT },
          spacing: { before: 120, after: 120, line: LINE_SPACING },
          alignment: AlignmentType.JUSTIFIED,
        }));
        break;

      case "list_item":
        paragraphs.push(new Paragraph({
          children: parseInlineFormatting(block.text, { font: FONT, size: FONT_SIZE }),
          indent: { left: 720, hanging: 360 }, // Bullet-style indent
          spacing: { before: 60, after: 60, line: LINE_SPACING },
          alignment: AlignmentType.JUSTIFIED,
        }));
        break;

      case "separator":
        paragraphs.push(new Paragraph({
          children: [new TextRun({ text: "" })],
          spacing: { before: 120, after: 120 },
        }));
        break;

      case "body":
      default:
        paragraphs.push(new Paragraph({
          children: parseInlineFormatting(block.text, { font: FONT, size: FONT_SIZE }),
          indent: { firstLine: FIRST_LINE_INDENT },
          spacing: { before: 0, after: 120, line: LINE_SPACING },
          alignment: AlignmentType.JUSTIFIED,
        }));
        break;
    }
  }

  // Se nao ha paragrafos, criar pelo menos um vazio
  if (!paragraphs.length) {
    paragraphs.push(new Paragraph({
      children: [new TextRun({ text: "", font: FONT, size: FONT_SIZE })],
    }));
  }

  // Montar documento
  const doc = new Document({
    creator: "CearIA v.1 by Ceara",
    title: title || "Minuta Juridica",
    description: "Documento gerado pelo CearIA v.1",
    sections: [{
      properties: {
        page: {
          margin: {
            top: MARGIN_TOP,
            bottom: MARGIN_BOTTOM,
            left: MARGIN_LEFT,
            right: MARGIN_RIGHT,
          },
        },
      },
      children: paragraphs,
    }],
  });

  // Gerar blob
  const blob = await Packer.toBlob(doc);
  return await blob.arrayBuffer();
}

// ── Helpers de parsing ──────────────────────────────────────────────────

/**
 * Remove cabecalho e rodape padrao das minutas (gerados pelo MinutaIA).
 */
function stripHeaderFooter(md) {
  let text = md;

  // Remover cabecalho (antes do primeiro heading significativo)
  // Padrao: linhas como "PROCURADORIA GERAL DO ESTADO", "Procuradoria ...", enderecos
  const headerPatterns = [
    /^(?:PROCURADORIA|ESTADO DE PERNAMBUCO|Rua\s|Av\.\s|CEP\s|Fone\s|Tel\s).*/gim,
  ];
  for (const pat of headerPatterns) {
    text = text.replace(pat, "");
  }

  // Remover rodape (assinaturas genericas do template)
  const footerPatterns = [
    /(?:Atenciosamente|Respeitosamente|Nestes termos,?\s*pede deferimento)[\s\S]{0,200}$/i,
  ];
  // Nao remover rodape se faz parte do conteudo significativo

  return text.trim();
}

/**
 * Parse markdown simples em blocos tipados.
 * @param {string} md
 * @returns {Array<{type:string, text:string}>}
 */
function parseMarkdown(md) {
  const lines = md.split("\n");
  const blocks = [];
  let currentBlock = null;

  for (const rawLine of lines) {
    const line = rawLine.trimEnd();

    // Heading
    const h1Match = line.match(/^#\s+(.+)/);
    const h2Match = line.match(/^##\s+(.+)/);
    const h3Match = line.match(/^###\s+(.+)/);

    if (h1Match) {
      if (currentBlock) blocks.push(currentBlock);
      blocks.push({ type: "heading1", text: h1Match[1].trim() });
      currentBlock = null;
      continue;
    }
    if (h2Match) {
      if (currentBlock) blocks.push(currentBlock);
      blocks.push({ type: "heading2", text: h2Match[1].trim() });
      currentBlock = null;
      continue;
    }
    if (h3Match) {
      if (currentBlock) blocks.push(currentBlock);
      blocks.push({ type: "heading3", text: h3Match[1].trim() });
      currentBlock = null;
      continue;
    }

    // Blockquote
    if (line.startsWith(">")) {
      const text = line.replace(/^>\s*/, "").trim();
      if (currentBlock && currentBlock.type === "blockquote") {
        currentBlock.text += " " + text;
      } else {
        if (currentBlock) blocks.push(currentBlock);
        currentBlock = { type: "blockquote", text };
      }
      continue;
    }

    // List item
    if (/^[-*+]\s/.test(line) || /^\d+\.\s/.test(line)) {
      if (currentBlock) blocks.push(currentBlock);
      const text = line.replace(/^[-*+]\s|^\d+\.\s/, "").trim();
      blocks.push({ type: "list_item", text });
      currentBlock = null;
      continue;
    }

    // Separator (---, ***, ___)
    if (/^[-*_]{3,}\s*$/.test(line)) {
      if (currentBlock) blocks.push(currentBlock);
      blocks.push({ type: "separator", text: "" });
      currentBlock = null;
      continue;
    }

    // Empty line = fim do bloco atual
    if (!line.trim()) {
      if (currentBlock) {
        blocks.push(currentBlock);
        currentBlock = null;
      }
      continue;
    }

    // Body text — acumular no bloco atual
    if (currentBlock && currentBlock.type === "body") {
      currentBlock.text += " " + line.trim();
    } else {
      if (currentBlock) blocks.push(currentBlock);
      currentBlock = { type: "body", text: line.trim() };
    }
  }

  if (currentBlock) blocks.push(currentBlock);

  return blocks.filter(b => b.text || b.type === "separator");
}

/**
 * Parse inline formatting (bold, italic) e retorna array de TextRun.
 * @param {string} text
 * @param {object} baseStyle — {font, size, italics?, bold?}
 * @returns {Array}
 */
function parseInlineFormatting(text, baseStyle) {
  const { TextRun } = docxLib;
  const runs = [];

  // Regex para **bold**, *italic*, ***bold+italic***
  const regex = /(\*{3})(.+?)\1|(\*{2})(.+?)\3|(\*{1})(.+?)\5/g;

  let lastIndex = 0;
  let match;

  while ((match = regex.exec(text)) !== null) {
    // Texto antes do match
    if (match.index > lastIndex) {
      const before = text.slice(lastIndex, match.index);
      if (before) {
        runs.push(new TextRun({
          text: before,
          font: baseStyle.font,
          size: baseStyle.size,
          bold: baseStyle.bold || false,
          italics: baseStyle.italics || false,
        }));
      }
    }

    if (match[1] === "***") {
      // Bold + Italic
      runs.push(new TextRun({
        text: match[2],
        font: baseStyle.font,
        size: baseStyle.size,
        bold: true,
        italics: true,
      }));
    } else if (match[3] === "**") {
      // Bold
      runs.push(new TextRun({
        text: match[4],
        font: baseStyle.font,
        size: baseStyle.size,
        bold: true,
        italics: baseStyle.italics || false,
      }));
    } else if (match[5] === "*") {
      // Italic
      runs.push(new TextRun({
        text: match[6],
        font: baseStyle.font,
        size: baseStyle.size,
        bold: baseStyle.bold || false,
        italics: true,
      }));
    }

    lastIndex = match.index + match[0].length;
  }

  // Texto restante
  if (lastIndex < text.length) {
    runs.push(new TextRun({
      text: text.slice(lastIndex),
      font: baseStyle.font,
      size: baseStyle.size,
      bold: baseStyle.bold || false,
      italics: baseStyle.italics || false,
    }));
  }

  // Se nao houve nenhum match, retornar texto inteiro
  if (!runs.length) {
    runs.push(new TextRun({
      text,
      font: baseStyle.font,
      size: baseStyle.size,
      bold: baseStyle.bold || false,
      italics: baseStyle.italics || false,
    }));
  }

  return runs;
}

/**
 * Converte markdown para Blob DOCX (conveniente para download).
 * @param {string} markdown
 * @param {object} [options]
 * @returns {Promise<Blob>}
 */
export async function markdownToDocxBlob(markdown, options = {}) {
  const buffer = await markdownToDocx(markdown, options);
  return new Blob([buffer], {
    type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  });
}

/**
 * Dispara download de DOCX no browser.
 * @param {string} markdown
 * @param {string} [filename="minuta.docx"]
 * @param {object} [options]
 */
export async function downloadDocx(markdown, filename = "minuta.docx", options = {}) {
  const blob = await markdownToDocxBlob(markdown, options);
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
}
