/**
 * CearIA v.1 (by Ceara) — Sidepanel Logic
 *
 * Orquestra a UI do sidepanel usando modulos ES diretamente (zero backend).
 * Fluxo principal: detectar request → carregar contexto → configurar → gerar via MinutaIA → exibir resultado.
 */

import * as minutaiaClient from "./modules/minutaia-client.js";
import { buildPayload, prepareDocuments, prepareModels } from "./modules/minutaia-payload.js";
import { loadContext, incluirManifestacao, clearCache, fetchPastaMetadata } from "./modules/attus-client.js";
import { extractForContext, extractText } from "./modules/pdf-extractor.js";
import { downloadDocx, markdownToDocx } from "./modules/docx-generator.js";
import * as storage from "./modules/storage.js";
import { getToken } from "./modules/attus-token.js";
import { PROMPTS, findPromptByTipo, listTiposPeca } from "./modules/prompts.js";

// ── State ───────────────────────────────────────────────────────────────

let currentRequest = null; // {demandaId, numeroPasta, processoId, manifestacaoTipo, attusToken}
let contextData = null;    // {content, fileName, pageCount, tokenCount, numeroPasta}
let extraDocuments = [];   // [{content, fileName, pageCount, tokenCount}]
let userModels = [];       // [{content, title, selected}]
let generatedMarkdown = "";
let generatedDocumentId = "";
let currentGeracaoId = null;
let isGenerating = false;
let activeNumeroPasta = ""; // pasta atualmente refletida no header (task 3/4)
let contextByPasta = {};    // cache por numeroPasta {content, fileName, pageCount, tokenCount}
let metadataByPasta = {};   // cache de metadados leves por numeroPasta
let metadataFetchInFlight = ""; // evita fetch duplicado

// ── DOM refs ────────────────────────────────────────────────────────────

const $ = (sel) => document.querySelector(sel);
const $$ = (sel) => document.querySelectorAll(sel);

const banner = $("#status-banner");
const procPasta = $("#proc-pasta");
const procTipo = $("#proc-tipo");
const ctxStatus = $("#contexto-status");
const ctxText = $("#ctx-text");
const btnRetryCtx = $("#btn-retry-ctx");
const pdfProgress = $("#pdf-progress");
const pdfBar = $("#pdf-bar");
const pdfMsg = $("#pdf-msg");
const selTipoPeca = $("#sel-tipo-peca");
const inputFiltro = $("#input-filtro-tipo");
const taPrompt = $("#ta-prompt");
const btnTogglePrompt = $("#btn-toggle-prompt");
const promptEditor = $("#prompt-editor");
const sliderEsforco = $("#slider-esforco");
const esforcoLabel = $("#esforco-label");
const btnGerar = $("#btn-gerar");
const resultadoSection = $("#resultado-section");
const resultadoContent = $("#resultado-content");
const thinkingSection = $("#thinking-section");
const thinkingLog = $("#thinking-log");
const btnDocx = $("#btn-docx");
const btnCopiar = $("#btn-copiar");
const btnIncluirManif = $("#btn-incluir-manif");
const settingsModal = $("#settings-modal");
const modelosList = $("#modelos-list");
const minutaiaIndicator = $("#minutaia-indicator");

// ── Helpers UI ──────────────────────────────────────────────────────────

function showBanner(msg, type = "loading") {
  banner.textContent = msg;
  banner.className = `banner ${type}`;
  banner.classList.remove("hidden");
}

function hideBanner() {
  banner.classList.add("hidden");
}

function setCtxStatus(text, status = "") {
  ctxText.textContent = text;
  ctxStatus.className = `ctx-status ${status}`;
}

/**
 * Atualiza o indicador visual de conexao com o MinutaIA no header.
 * Estados: 'unknown' | 'loading' | 'connected' | 'disconnected'
 */
function setMinutaiaIndicator(state, userLabel = "") {
  if (!minutaiaIndicator) return;
  minutaiaIndicator.classList.remove("is-unknown", "is-loading", "is-connected", "is-disconnected");
  minutaiaIndicator.classList.add(`is-${state}`);
  const text = minutaiaIndicator.querySelector(".mi-text");
  if (!text) return;
  switch (state) {
    case "connected":
      text.textContent = "MinutaIA ✓";
      minutaiaIndicator.title = userLabel
        ? `MinutaIA conectado (${userLabel}). Clique para abrir configuracoes.`
        : "MinutaIA conectado. Clique para abrir configuracoes.";
      break;
    case "disconnected":
      text.textContent = "MinutaIA ✗";
      minutaiaIndicator.title = "MinutaIA desconectado. Clique para configurar credenciais.";
      break;
    case "loading":
      text.textContent = "MinutaIA";
      minutaiaIndicator.title = "Conectando ao MinutaIA...";
      break;
    default:
      text.textContent = "MinutaIA";
      minutaiaIndicator.title = "Verificando sessao MinutaIA...";
  }
}

/** Converter markdown simples para HTML. */
function mdToHtml(md) {
  return md
    .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
    .replace(/^### (.+)$/gm, "<h3>$1</h3>")
    .replace(/^## (.+)$/gm, "<h2>$1</h2>")
    .replace(/^# (.+)$/gm, "<h1>$1</h1>")
    .replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>")
    .replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>")
    .replace(/\*(.+?)\*/g, "<em>$1</em>")
    .replace(/^> (.+)$/gm, "<blockquote>$1</blockquote>")
    .replace(/^[-*] (.+)$/gm, "<li>$1</li>")
    .replace(/\n\n/g, "</p><p>")
    .replace(/\n/g, "<br>")
    .replace(/^/, "<p>").replace(/$/, "</p>");
}

// ── Init ────────────────────────────────────────────────────────────────

async function init() {
  // Popular dropdown de tipos de peca dinamicamente a partir do mapa_prompts
  populateTiposPecaDropdown();

  // Carregar preferencias
  const prefs = await storage.getPreferences();
  sliderEsforco.value = prefs.effort;
  esforcoLabel.textContent = prefs.effort;

  // Setar verbosidade
  $$(".toggle-btn").forEach(btn => {
    btn.classList.toggle("active", btn.dataset.verb === prefs.verbosity);
  });

  // Rigoroso
  $("#chk-rigoroso").checked = prefs.rigoroso !== false;

  // Observar novos requests PRIMEIRO (nao perder requests que cheguem durante init)
  let handledPendingId = null;
  storage.onGenerateRequest((req) => {
    if (!req) return;
    // Evitar double-dispatch com o consumeGenerateRequest abaixo
    const id = req.timestamp || 0;
    if (id && id === handledPendingId) return;
    handledPendingId = id;
    console.log("[panel] onGenerateRequest disparou:", { demandaId: req.demandaId, numeroPasta: req.numeroPasta, ts: id });
    storage.consumeGenerateRequest(); // Limpar
    handleGenerateRequest(req);
  });

  // Observar light_current_context para reagir a trocas de pasta / fechamento de aba (Task 3/4)
  observeActiveTabContext();

  // Render inicial do header com base no contexto ja persistido (se houver)
  // Mesclar com metadados cacheados se existirem, depois disparar fetch se necessario
  const curCtx = await chrome.storage.local.get("light_current_context");
  const savedCtx = curCtx.light_current_context || null;
  if (savedCtx && savedCtx.numeroPasta) {
    const cached = metadataByPasta[savedCtx.numeroPasta];
    renderPastaHeader(cached ? { ...cached, ...savedCtx, materia: cached.materia || "", assuntos: cached.assuntos || "", localDistribuicao: cached.localDistribuicao || "", numeroProcesso: cached.numeroProcesso || "" } : savedCtx);
    ensurePastaMetadata(savedCtx.numeroPasta, savedCtx.attusToken || "");
  } else {
    renderPastaHeader(null);
  }

  // Verificar request pendente ja gravado pelo SW
  const pending = await storage.consumeGenerateRequest();
  if (pending) {
    handledPendingId = pending.timestamp || 0;
    console.log("[panel] pending consumido no init:", { demandaId: pending.demandaId, numeroPasta: pending.numeroPasta });
    handleGenerateRequest(pending);
  }

  // Event listeners
  setupEventListeners();

  // (historico removido)

  // Check MinutaIA session em background (nao bloquear fluxo de contexto)
  checkMinutaiaSession().catch(e => console.warn("[panel] checkMinutaiaSession falhou:", e));
}

// ── Populacao dinamica do dropdown de tipos ─────────────────────────────

function populateTiposPecaDropdown() {
  // Preservar a opcao placeholder "Selecionar..."
  while (selTipoPeca.options.length > 1) selTipoPeca.remove(1);
  const tipos = listTiposPeca();
  for (const t of tipos) {
    const opt = document.createElement("option");
    opt.value = t.id;
    opt.textContent = t.label;
    selTipoPeca.appendChild(opt);
  }
}

// ── Header da pasta atual (Task 4) ──────────────────────────────────────

function renderPastaHeader(ctx) {
  const header = $("#proc-header");
  const pastaEl = $("#proc-pasta");
  const tipo = procTipo;

  // Helpers: mostrar/esconder row
  function setRow(id, value) {
    const row = $(`#${id}-row`);
    const span = $(`#${id}`);
    if (!row || !span) return;
    if (value) {
      span.textContent = value;
      row.classList.remove("hidden");
    } else {
      row.classList.add("hidden");
    }
  }

  if (!ctx || !ctx.numeroPasta) {
    pastaEl.textContent = "—";
    header.classList.add("empty");
    tipo.textContent = "";
    tipo.classList.add("hidden");
    setRow("proc-numero", "");
    setRow("proc-materia", "");
    setRow("proc-local", "");
    setRow("proc-assuntos", "");
    setCtxStatus("Aguardando navegacao para uma pasta digital...", "");
    activeNumeroPasta = "";
    return;
  }

  header.classList.remove("empty");
  pastaEl.textContent = ctx.numeroPasta;
  tipo.textContent = "";
  tipo.classList.add("hidden");

  // Preencher campos conforme disponibilidade
  setRow("proc-numero", ctx.numeroProcesso || "");
  setRow("proc-materia", ctx.materia || "");
  setRow("proc-local", ctx.localDistribuicao || "");
  setRow("proc-assuntos", ctx.assuntos || "");

  // Quando a pasta muda, resetar estado local do painel
  if (activeNumeroPasta && activeNumeroPasta !== ctx.numeroPasta) {
    console.log(`[panel] Pasta mudou de ${activeNumeroPasta} -> ${ctx.numeroPasta}, resetando contexto`);
    resetSidepanelForNewPasta();
  }
  activeNumeroPasta = ctx.numeroPasta;

  // Se ainda nao ha contextData carregado, mostra status preparatorio
  if (!contextData) {
    setCtxStatus("Clique em um botao IA do Attus para carregar o contexto", "");
  }
}

function resetSidepanelForNewPasta() {
  contextData = null;
  extraDocuments = [];
  generatedMarkdown = "";
  generatedDocumentId = "";
  currentGeracaoId = null;
  currentRequest = null;
  resultadoSection.classList.add("hidden");
  thinkingSection.classList.add("hidden");
  btnIncluirManif.classList.add("hidden");
  procTipo.textContent = "";
  procTipo.classList.add("hidden");
  setCtxStatus("Aguardando...", "");
  renderDocsList();
  updateButtonState();
  hideBanner();
}

// ── Fetch leve de metadados da pasta (antes do click no IA) ─────────────

/**
 * Busca metadados do processo (RSQL leve ~300ms) e popula o header
 * imediatamente. Usa cache para nao refazer a chamada na mesma pasta.
 * Chamado sempre que o numeroPasta muda (broadcast do content script).
 */
async function ensurePastaMetadata(numeroPasta, browserToken) {
  if (!numeroPasta) return;
  // Cache hit
  if (metadataByPasta[numeroPasta]) {
    renderPastaHeader(metadataByPasta[numeroPasta]);
    return;
  }
  // Evitar fetch duplicado se ja esta em andamento para esta pasta
  if (metadataFetchInFlight === numeroPasta) return;
  metadataFetchInFlight = numeroPasta;

  try {
    console.log(`[panel] Buscando metadados da pasta ${numeroPasta}...`);
    const meta = await fetchPastaMetadata(numeroPasta, browserToken || "");
    if (meta) {
      metadataByPasta[numeroPasta] = meta;
      // So renderiza se ainda estamos na mesma pasta
      if (activeNumeroPasta === numeroPasta || !activeNumeroPasta) {
        renderPastaHeader(meta);
      }
      console.log(`[panel] Metadados carregados:`, meta.materia || "(sem materia)", meta.assuntos || "(sem assuntos)");
    }
  } catch (e) {
    console.warn("[panel] Falha ao buscar metadados:", e);
  } finally {
    if (metadataFetchInFlight === numeroPasta) metadataFetchInFlight = "";
  }
}

// ── Observacao do contexto (Task 3) ─────────────────────────────────────

function observeActiveTabContext() {
  chrome.storage.onChanged.addListener((changes, area) => {
    if (area !== "local") return;
    if (changes.light_current_context) {
      const nv = changes.light_current_context.newValue;
      if (!nv) {
        // Contexto removido (aba fechada). Resetar visual.
        renderPastaHeader(null);
        resetSidepanelForNewPasta();
        return;
      }
      // Mesclar broadcast do content script (que tem apenas dados do DOM)
      // com metadados ja cacheados da API (que tem materia, assuntos, etc).
      // Isso evita que re-broadcasts do content script apaguem campos ja populados.
      const cached = metadataByPasta[nv.numeroPasta];
      const merged = cached
        ? { ...cached, ...nv, materia: cached.materia || nv.materia || "", assuntos: cached.assuntos || nv.assuntos || "", localDistribuicao: cached.localDistribuicao || nv.localDistribuicao || "", numeroProcesso: cached.numeroProcesso || nv.numeroProcesso || "" }
        : nv;
      renderPastaHeader(merged);

      // Se a pasta mudou ou nunca buscamos metadados, disparar fetch leve
      if (nv.numeroPasta && nv.numeroPasta !== activeNumeroPasta) {
        ensurePastaMetadata(nv.numeroPasta, nv.attusToken || "");
      } else if (nv.numeroPasta && !metadataByPasta[nv.numeroPasta]) {
        ensurePastaMetadata(nv.numeroPasta, nv.attusToken || "");
      }
    }
  });
}

// ── MinutaIA Session ────────────────────────────────────────────────────

async function checkMinutaiaSession() {
  setMinutaiaIndicator("loading");
  const session = await minutaiaClient.checkSession();
  if (session) {
    const userLabel = session.user?.name || session.user?.email || "";
    console.log("[panel] MinutaIA session ativa:", userLabel);
    setMinutaiaIndicator("connected", userLabel);
    return true;
  }

  // Tentar login automatico
  const creds = await storage.getMinutaiaCredentials();
  if (creds.email && creds.password) {
    showBanner("Conectando ao MinutaIA...", "loading");
    const ok = await minutaiaClient.login(creds.email, creds.password);
    if (ok) {
      hideBanner();
      console.log("[panel] MinutaIA login OK");
      const info = minutaiaClient.getUserInfo();
      setMinutaiaIndicator("connected", info?.name || info?.email || creds.email);
      return true;
    } else {
      showBanner("Falha ao conectar ao MinutaIA. Verifique credenciais.", "error");
      setMinutaiaIndicator("disconnected");
      return false;
    }
  }

  showBanner("MinutaIA nao autenticado. Configure em ⚙ Configuracoes.", "warning");
  setMinutaiaIndicator("disconnected");
  return false;
}

// ── Handle Generate Request (do content script) ─────────────────────────

async function handleGenerateRequest(req) {
  console.log("[panel] handleGenerateRequest start:", req);
  currentRequest = req;
  generatedMarkdown = "";
  generatedDocumentId = "";
  resultadoSection.classList.add("hidden");
  thinkingSection.classList.add("hidden");
  btnIncluirManif.classList.add("hidden");

  // Atualizar UI com info do processo
  if (req.numeroPasta) {
    const header = $("#proc-header");
    if (header) header.classList.remove("empty");
    procPasta.textContent = req.numeroPasta;
    activeNumeroPasta = req.numeroPasta;
  }
  // Tipo/status em badge
  if (req.manifestacaoTipo) {
    procTipo.textContent = req.manifestacaoTipo;
    procTipo.classList.remove("hidden");
  } else {
    procTipo.textContent = "";
    procTipo.classList.add("hidden");
  }

  // Auto-selecionar tipo de peca + carregar prompt padrao
  if (req.manifestacaoTipo) {
    autoSelectTipoPecaAndPrompt(req.manifestacaoTipo);
  }

  // Cache hit: se ja temos o contexto para essa pasta, reutilizar (Task 3)
  if (req.numeroPasta && contextByPasta[req.numeroPasta]) {
    console.log(`[panel] Cache hit para pasta ${req.numeroPasta}`);
    contextData = contextByPasta[req.numeroPasta];
    renderDocsList();
    setCtxStatus(
      `${contextData.fileName} — ${(contextData.tokenCount / 1000).toFixed(0)}k tokens`,
      "loaded"
    );
    btnRetryCtx.classList.remove("hidden");
    updateButtonState();
    return;
  }

  // Carregar contexto (PDF)
  await loadProcessContext(req);
}

/**
 * Auto-seleciona o tipo de peca no dropdown e carrega o prompt padrao
 * do mapa_prompts (task 2).
 */
function autoSelectTipoPecaAndPrompt(tipo) {
  const match = findPromptByTipo(tipo);
  if (match) {
    // Garantir que existe uma option com esse valor (pode nao estar visivel pelo filtro)
    let opt = Array.from(selTipoPeca.options).find(o => o.value === match.key);
    if (!opt) {
      opt = document.createElement("option");
      opt.value = match.key;
      opt.textContent = match.key;
      selTipoPeca.appendChild(opt);
    }
    selTipoPeca.value = match.key;
    // Preencher textarea do prompt (user pode editar)
    if (taPrompt) {
      taPrompt.value = match.prompt;
      // Abrir editor de prompt para o usuario ver o que foi carregado
      promptEditor.classList.remove("hidden");
    }
    updateButtonState();
    console.log(`[panel] Auto-fill: tipo='${match.key}', prompt len=${match.prompt.length}`);
    return;
  }

  // Se nao houver match, cair para "Outra (prompt livre)"
  selTipoPeca.value = "__outra__";
  if (taPrompt && !taPrompt.value) {
    taPrompt.value = "";
  }
  updateButtonState();
}

// Compat: mantem nome antigo para callers (agora chama a versao nova)
function autoSelectTipoPeca(tipo) {
  autoSelectTipoPecaAndPrompt(tipo);
}

// ── Load Process Context ────────────────────────────────────────────────

async function loadProcessContext(req) {
  setCtxStatus("Carregando PDF...", "loading");
  btnRetryCtx.classList.add("hidden");
  pdfProgress.classList.remove("hidden");
  pdfMsg.textContent = "Baixando PDF unificado...";
  pdfBar.style.width = "10%";

  try {
    // 1. Buscar PDF bytes do Attus
    const result = await loadContext({
      demandaId: req.demandaId,
      browserToken: req.attusToken,
      numeroPasta: req.numeroPasta,
      processoId: req.processoId,
    });

    // Propagar demandaId/processoId resolvidos para o currentRequest (necessario
    // para "Incluir Manifestacao" quando o content script so tinha numeroPasta).
    if (result.demandaId && !req.demandaId) {
      currentRequest.demandaId = result.demandaId;
    }
    if (result.processoId && !req.processoId) {
      currentRequest.processoId = result.processoId;
    }

    // Atualizar header com metadados do processo (materia, assuntos, etc)
    renderPastaHeader({
      numeroPasta: result.numeroPasta || req.numeroPasta,
      numeroProcesso: result.numeroProcesso || "",
      materia: result.materia || "",
      localDistribuicao: result.localDistribuicao || "",
      assuntos: result.assuntos || "",
    });

    pdfBar.style.width = "50%";
    pdfMsg.textContent = "Extraindo texto do PDF...";

    // 2. Extrair texto com pdf.js
    const extracted = await extractForContext(
      result.pdfBytes,
      result.numeroPasta || req.numeroPasta,
      (page, total) => {
        const pct = 50 + Math.floor((page / total) * 50);
        pdfBar.style.width = `${pct}%`;
        pdfMsg.textContent = `Extraindo pagina ${page}/${total}...`;
      }
    );

    contextData = extracted;
    pdfBar.style.width = "100%";
    pdfProgress.classList.add("hidden");

    // Cache por numeroPasta (Task 3: reaproveitar entre cliques na mesma pasta)
    const pastaKey = result.numeroPasta || req.numeroPasta;
    if (pastaKey) {
      contextByPasta[pastaKey] = extracted;
    }

    // Atualizar UI
    setCtxStatus(
      `${extracted.fileName} — ${(extracted.tokenCount / 1000).toFixed(0)}k tokens`,
      "loaded"
    );
    btnRetryCtx.classList.remove("hidden");

    // Adicionar ao docs-list
    renderDocsList();
    updateButtonState();

    // Atualizar info do processo
    if (extracted.numeroPasta) {
      procPasta.textContent = extracted.numeroPasta;
    }

  } catch (e) {
    console.error("[panel] Erro ao carregar contexto:", e);
    pdfProgress.classList.add("hidden");
    setCtxStatus(`Erro: ${e.message}`, "error");
    btnRetryCtx.classList.remove("hidden");
  }
}

// ── Render Documents List ───────────────────────────────────────────────

function renderDocsList() {
  const docsList = $("#docs-list");
  docsList.innerHTML = "";

  // Documento principal (processo)
  if (contextData) {
    const div = document.createElement("div");
    div.className = "doc-item process-doc";
    div.innerHTML = `
      <span class="doc-name">${contextData.fileName}</span>
      <span class="doc-meta">${contextData.pageCount}p / ${(contextData.tokenCount/1000).toFixed(0)}k</span>
    `;
    docsList.appendChild(div);
  }

  // Documentos extras
  for (let i = 0; i < extraDocuments.length; i++) {
    const doc = extraDocuments[i];
    const div = document.createElement("div");
    div.className = "doc-item";
    div.innerHTML = `
      <span class="doc-name">${doc.fileName}</span>
      <span class="doc-meta">${doc.pageCount}p / ${(doc.tokenCount/1000).toFixed(0)}k</span>
      <button class="btn-remove" data-idx="${i}">✕</button>
    `;
    div.querySelector(".btn-remove").addEventListener("click", () => {
      extraDocuments.splice(i, 1);
      renderDocsList();
    });
    docsList.appendChild(div);
  }
}

// ── Update Button State ─────────────────────────────────────────────────

function updateButtonState() {
  const hasContext = !!contextData;
  const hasTipo = !!selTipoPeca.value;
  btnGerar.disabled = !hasContext || !hasTipo || isGenerating;
}

// ── Generate ────────────────────────────────────────────────────────────

async function startGeneration() {
  if (isGenerating || !contextData) return;

  // Verificar sessao MinutaIA
  if (!minutaiaClient.isAuthenticated()) {
    const ok = await checkMinutaiaSession();
    if (!ok) return;
  }

  isGenerating = true;
  generatedMarkdown = "";
  generatedDocumentId = "";
  btnGerar.disabled = true;
  btnGerar.textContent = "⏳ Gerando...";
  resultadoSection.classList.remove("hidden");
  resultadoContent.innerHTML = '<div class="spinner"></div> Iniciando geracao...';
  thinkingSection.classList.remove("hidden");
  thinkingLog.textContent = "";
  btnIncluirManif.classList.add("hidden");
  hideBanner();

  // Salvar preferencias
  const verbosity = $(".toggle-btn.active")?.dataset.verb || "long";
  const effort = parseInt(sliderEsforco.value);
  const rigoroso = $("#chk-rigoroso").checked;
  await storage.setPreferences({ effort, verbosity, rigoroso });

  // Preparar documentos
  const allDocs = [];
  if (contextData) {
    allDocs.push({
      content: contextData.content,
      fileName: contextData.fileName,
      pageCount: contextData.pageCount,
      tokenCount: contextData.tokenCount,
    });
  }
  for (const doc of extraDocuments) {
    allDocs.push(doc);
  }

  const documents = prepareDocuments(allDocs);

  // Preparar modelos selecionados
  const selectedModels = userModels.filter(m => m.selected);
  const models = selectedModels.length > 0 ? prepareModels(selectedModels) : null;

  // Obter prompt
  let prompt = taPrompt.value.trim();
  if (!prompt) {
    const tipoPeca = selTipoPeca.value;
    const customPrompt = await storage.buscarPrompt(tipoPeca);
    prompt = customPrompt?.prompt || getDefaultPrompt(tipoPeca);
  }

  // Construir payload
  const payload = buildPayload({
    prompt,
    documents,
    models,
    effort,
    verbosity,
    rigoroso,
    jurisprudencia: true,
    legislacao: true,
  });

  // Salvar geracao no historico (status: generating)
  currentGeracaoId = await storage.salvarGeracao({
    demanda_id: currentRequest?.demandaId || "",
    numero_pasta: currentRequest?.numeroPasta || "",
    tipo_peca: selTipoPeca.value,
    tipo_peca_nome: selTipoPeca.options[selTipoPeca.selectedIndex]?.text || "",
    prompt: prompt.substring(0, 200),
    status: "generating",
  });

  try {
    // Enviar para MinutaIA
    const response = await minutaiaClient.generateStream(payload);

    // Consumir SSE stream
    await minutaiaClient.consumeSSEStream(response, handleSSEEvent);

    // Buscar documento se temos documentId
    if (generatedDocumentId) {
      const doc = await minutaiaClient.fetchDocument(generatedDocumentId);
      if (doc && doc.content) {
        generatedMarkdown = doc.content;
        resultadoContent.innerHTML = mdToHtml(generatedMarkdown);
      }
    }

    // Atualizar geracao
    if (currentGeracaoId) {
      await storage.atualizarGeracao(currentGeracaoId, {
        status: "completed",
        document_id: generatedDocumentId,
        resultado_preview: generatedMarkdown.substring(0, 500),
      });
    }

    // Mostrar botao incluir manifestacao
    if (currentRequest?.demandaId) {
      btnIncluirManif.classList.remove("hidden");
    }

    showBanner("Geracao concluida!", "success");
    setTimeout(hideBanner, 3000);

  } catch (e) {
    console.error("[panel] Erro na geracao:", e);
    resultadoContent.innerHTML = `<p style="color:var(--error)">Erro: ${e.message}</p>`;
    showBanner(`Erro: ${e.message}`, "error");

    if (currentGeracaoId) {
      await storage.atualizarGeracao(currentGeracaoId, {
        status: "error",
        error: e.message,
      });
    }
  } finally {
    isGenerating = false;
    btnGerar.disabled = false;
    btnGerar.textContent = "▶ Gerar Minuta";
    updateButtonState();
  }
}

function handleSSEEvent(event) {
  switch (event.type) {
    case "chat_created":
      console.log("[panel] Chat criado:", event.chatId);
      break;

    case "thinking":
      thinkingLog.textContent += event.text + "\n";
      thinkingLog.scrollTop = thinkingLog.scrollHeight;
      break;

    case "text":
      generatedMarkdown += event.content || "";
      resultadoContent.innerHTML = mdToHtml(generatedMarkdown);
      resultadoContent.scrollTop = resultadoContent.scrollHeight;
      break;

    case "done":
      generatedDocumentId = event.documentId || "";
      console.log("[panel] Geracao concluida. docId:", generatedDocumentId);
      break;

    case "error":
      console.error("[panel] SSE erro:", event.message);
      showBanner(`Erro: ${event.message}`, "error");
      break;
  }
}

// ── Default Prompts ─────────────────────────────────────────────────────

function getDefaultPrompt(tipoPeca) {
  const prompts = {
    contestacao: "Elabore uma contestacao completa para este processo, seguindo a tecnica processual adequada e a jurisprudencia aplicavel.",
    apelacao: "Elabore uma apelacao completa contra a sentenca proferida neste processo.",
    agravo_instrumento: "Elabore um agravo de instrumento contra a decisao interlocutoria proferida neste processo.",
    embargos_declaracao: "Elabore embargos de declaracao apontando as omissoes, contradicoes ou obscuridades na decisao.",
    contrarrazoes_recurso: "Elabore contrarrazoes de recurso, refutando os argumentos do recorrente.",
    contrarrazoes_resp_re: "Elabore contrarrazoes ao Recurso Especial/Extraordinario interposto.",
    recurso_inominado: "Elabore recurso inominado contra a sentenca proferida no Juizado Especial.",
    recurso_especial: "Elabore recurso especial com base nas hipoteses do art. 105, III, da CF.",
    recurso_extraordinario: "Elabore recurso extraordinario com base nas hipoteses do art. 102, III, da CF.",
    manifestacao_previa: "Elabore manifestacao previa sobre os fatos e documentos apresentados.",
    alegacoes_finais: "Elabore alegacoes finais, sintetizando os fatos e fundamentos juridicos favoraveis.",
    dispensa_recurso: "Elabore requerimento de dispensa de recurso, fundamentando a desnecessidade.",
    dispensa_agravo: "Elabore requerimento de dispensa de agravo, fundamentando a desnecessidade.",
    outra: "Elabore a peca processual adequada para este processo.",
  };
  return prompts[tipoPeca] || prompts.outra;
}

// ── DOCX Download ───────────────────────────────────────────────────────

async function handleDocxDownload() {
  if (!generatedMarkdown) return;

  btnDocx.textContent = "⏳ Gerando...";
  btnDocx.disabled = true;

  try {
    const tipoPeca = selTipoPeca.options[selTipoPeca.selectedIndex]?.text || "Minuta";
    const pasta = currentRequest?.numeroPasta || "";
    const filename = pasta
      ? `${tipoPeca} - Pasta ${pasta}.docx`
      : `${tipoPeca}.docx`;

    await downloadDocx(generatedMarkdown, filename, { title: tipoPeca });
    btnDocx.textContent = "✓ Salvo!";
    setTimeout(() => { btnDocx.textContent = "💾 DOCX"; }, 2000);
  } catch (e) {
    console.error("[panel] Erro DOCX:", e);
    btnDocx.textContent = "❌ Erro";
    setTimeout(() => { btnDocx.textContent = "💾 DOCX"; }, 2000);
  } finally {
    btnDocx.disabled = false;
  }
}

// ── Copy ────────────────────────────────────────────────────────────────

async function handleCopy() {
  if (!generatedMarkdown) return;
  try {
    // Copiar HTML (formatado) e texto
    const html = mdToHtml(generatedMarkdown);
    const blob = new Blob([html], { type: "text/html" });
    const textBlob = new Blob([generatedMarkdown], { type: "text/plain" });

    await navigator.clipboard.write([
      new ClipboardItem({
        "text/html": blob,
        "text/plain": textBlob,
      }),
    ]);

    btnCopiar.textContent = "✓ Copiado!";
    setTimeout(() => { btnCopiar.textContent = "📋 Copiar"; }, 2000);
  } catch {
    // Fallback: copiar como texto
    await navigator.clipboard.writeText(generatedMarkdown);
    btnCopiar.textContent = "✓ Copiado!";
    setTimeout(() => { btnCopiar.textContent = "📋 Copiar"; }, 2000);
  }
}

// ── Incluir Manifestacao no Attus ───────────────────────────────────────

async function handleIncluirManifestacao() {
  if (!currentRequest?.demandaId || !generatedMarkdown) return;

  btnIncluirManif.disabled = true;
  btnIncluirManif.textContent = "⏳ Incluindo...";

  try {
    // Gerar DOCX bytes para WOPI upload
    let docxBytes = null;
    try {
      docxBytes = await markdownToDocx(generatedMarkdown);
    } catch (e) {
      console.warn("[panel] Erro ao gerar DOCX para WOPI:", e);
    }

    const result = await incluirManifestacao({
      browserToken: currentRequest.attusToken,
      demandaId: currentRequest.demandaId,
      processoId: currentRequest.processoId,
      tipoPeca: selTipoPeca.value,
      tipoPecaNome: selTipoPeca.options[selTipoPeca.selectedIndex]?.text || "",
      modo: "proxy",
      docxBytes,
    });

    if (result.ok) {
      btnIncluirManif.textContent = "✓ Manifestacao incluida!";
      btnIncluirManif.classList.add("success");

      // Salvar para badges no content script
      const created = await chrome.storage.local.get("light_created_manifestacoes");
      const list = created.light_created_manifestacoes || [];
      list.push({
        demandaId: currentRequest.demandaId,
        manifestacaoId: result.manifestacaoId,
        tipoDocumento: result.tipoDocumento?.nome || "",
        observacao: result.observacao,
        timestamp: Date.now(),
      });
      // Manter ultimas 50
      if (list.length > 50) list.splice(0, list.length - 50);
      await chrome.storage.local.set({ light_created_manifestacoes: list });

      // Atualizar geracao
      if (currentGeracaoId) {
        await storage.atualizarGeracao(currentGeracaoId, {
          manifestacao_attus_id: result.manifestacaoId,
          documento_id: result.documentoId,
        });
      }

      showBanner(
        result.reutilizada
          ? "Manifestacao reutilizada com sucesso!"
          : "Manifestacao criada com sucesso!",
        "success"
      );
    }
  } catch (e) {
    console.error("[panel] Erro ao incluir manifestacao:", e);
    btnIncluirManif.textContent = "❌ Erro";
    btnIncluirManif.classList.add("error");
    showBanner(`Erro: ${e.message}`, "error");
  }

  setTimeout(() => {
    btnIncluirManif.textContent = "Incluir no Attus";
    btnIncluirManif.className = "btn-attus-sm";
    btnIncluirManif.disabled = false;
  }, 3000);
}

// ── File Upload (Extra PDFs) ────────────────────────────────────────────

async function handleFileUpload(files) {
  for (const file of files) {
    if (!file.name.endsWith(".pdf")) continue;

    try {
      showBanner(`Extraindo texto de ${file.name}...`, "loading");
      const buffer = await file.arrayBuffer();
      const result = await extractText(buffer);

      extraDocuments.push({
        content: result.content,
        fileName: file.name,
        pageCount: result.pageCount,
        tokenCount: result.tokenCount,
      });

      renderDocsList();
      hideBanner();
    } catch (e) {
      console.error(`[panel] Erro ao processar ${file.name}:`, e);
      showBanner(`Erro ao processar ${file.name}: ${e.message}`, "error");
    }
  }
}

// ── Modelos de Referencia ───────────────────────────────────────────────

function renderModelos() {
  modelosList.innerHTML = "";
  if (userModels.length === 0) {
    modelosList.innerHTML = '<div class="modelos-empty">Nenhum modelo carregado</div>';
    return;
  }

  for (let i = 0; i < userModels.length; i++) {
    const m = userModels[i];
    const div = document.createElement("div");
    div.className = "modelo-item";
    div.innerHTML = `
      <label>
        <input type="checkbox" ${m.selected ? "checked" : ""} data-idx="${i}">
        <span class="modelo-name">${m.title}</span>
      </label>
      <button class="btn-remove" data-idx="${i}">✕</button>
    `;
    div.querySelector("input").addEventListener("change", (e) => {
      userModels[i].selected = e.target.checked;
    });
    div.querySelector(".btn-remove").addEventListener("click", () => {
      userModels.splice(i, 1);
      renderModelos();
    });
    modelosList.appendChild(div);
  }
}

// ── Settings ────────────────────────────────────────────────────────────

async function loadSettings() {
  const cfg = await storage.getConfig();
  $("#set-minutaia-email").value = cfg.minutaia_email || "";
  $("#set-minutaia-pass").value = cfg.minutaia_password || "";
  // Atualizar hint com o status atual da sessao
  const statusHint = $("#set-minutaia-status");
  if (statusHint) {
    if (minutaiaClient.isAuthenticated()) {
      const info = minutaiaClient.getUserInfo() || {};
      statusHint.textContent = `Conectado: ${info.name || info.email || ""}`.trim();
      statusHint.className = "field-hint success";
    } else if (cfg.minutaia_email) {
      statusHint.textContent = "Credenciais salvas, sessao inativa";
      statusHint.className = "field-hint";
    } else {
      statusHint.textContent = "Nao configurado";
      statusHint.className = "field-hint";
    }
  }
}

async function saveSettings() {
  const statusEl = $("#settings-status");
  try {
    await storage.setConfig({
      minutaia_email: $("#set-minutaia-email").value.trim(),
      minutaia_password: $("#set-minutaia-pass").value,
    });

    statusEl.textContent = "Salvo!";
    statusEl.className = "settings-status success";

    // Re-tentar login MinutaIA
    const email = $("#set-minutaia-email").value.trim();
    const pass = $("#set-minutaia-pass").value;
    if (email && pass) {
      statusEl.textContent = "Conectando ao MinutaIA...";
      setMinutaiaIndicator("loading");
      const ok = await minutaiaClient.login(email, pass);
      if (ok) {
        const info = minutaiaClient.getUserInfo() || {};
        setMinutaiaIndicator("connected", info.name || info.email || email);
        statusEl.textContent = "Conectado ao MinutaIA!";
        statusEl.className = "settings-status success";
        hideBanner();
      } else {
        setMinutaiaIndicator("disconnected");
        statusEl.textContent = "Erro ao conectar ao MinutaIA.";
        statusEl.className = "settings-status error";
      }
      loadSettings(); // atualizar hint
    }
  } catch (e) {
    statusEl.textContent = `Erro: ${e.message}`;
    statusEl.className = "settings-status error";
  }
}

async function clearMinutaiaCredentialsAction() {
  const statusEl = $("#settings-status");
  try {
    setMinutaiaIndicator("loading");
    await minutaiaClient.logout();
    await storage.clearMinutaiaCredentials();
    $("#set-minutaia-email").value = "";
    $("#set-minutaia-pass").value = "";
    setMinutaiaIndicator("disconnected");
    statusEl.textContent = "Credenciais removidas e sessao desconectada.";
    statusEl.className = "settings-status success";
    loadSettings();
  } catch (e) {
    console.error("[panel] Erro ao limpar credenciais MinutaIA:", e);
    statusEl.textContent = `Erro: ${e.message}`;
    statusEl.className = "settings-status error";
  }
}

// ── Event Listeners ─────────────────────────────────────────────────────

function setupEventListeners() {
  // Gerar
  btnGerar.addEventListener("click", startGeneration);

  // Tipo de peca
  selTipoPeca.addEventListener("change", updateButtonState);

  // Filtro tipo
  inputFiltro.addEventListener("input", () => {
    const q = inputFiltro.value.toLowerCase();
    Array.from(selTipoPeca.options).forEach(opt => {
      if (!opt.value) return; // skip placeholder
      opt.hidden = q && !opt.text.toLowerCase().includes(q);
    });
  });

  // Prompt toggle
  btnTogglePrompt.addEventListener("click", () => {
    promptEditor.classList.toggle("hidden");
  });

  // Esforco slider
  sliderEsforco.addEventListener("input", () => {
    esforcoLabel.textContent = sliderEsforco.value;
  });

  // Verbosidade toggle
  $$(".toggle-btn").forEach(btn => {
    btn.addEventListener("click", () => {
      $$(".toggle-btn").forEach(b => b.classList.remove("active"));
      btn.classList.add("active");
    });
  });

  // DOCX
  btnDocx.addEventListener("click", handleDocxDownload);

  // Copy
  btnCopiar.addEventListener("click", handleCopy);

  // Incluir manifestacao
  btnIncluirManif.addEventListener("click", handleIncluirManifestacao);

  // Retry contexto
  btnRetryCtx.addEventListener("click", () => {
    if (currentRequest) {
      clearCache(currentRequest.demandaId);
      // Limpar tambem o cache local por numeroPasta
      const key = currentRequest.numeroPasta || activeNumeroPasta;
      if (key) delete contextByPasta[key];
      contextData = null;
      loadProcessContext(currentRequest);
    }
  });

  // Limpar
  $("#btn-limpar").addEventListener("click", () => {
    currentRequest = null;
    contextData = null;
    extraDocuments = [];
    generatedMarkdown = "";
    generatedDocumentId = "";
    renderPastaHeader(null);
    setCtxStatus("Aguardando...", "");
    resultadoSection.classList.add("hidden");
    thinkingSection.classList.add("hidden");
    btnIncluirManif.classList.add("hidden");
    renderDocsList();
    hideBanner();
    updateButtonState();
  });

  // Settings
  function openSettings() {
    loadSettings();
    settingsModal.classList.remove("hidden");
  }
  $("#btn-settings").addEventListener("click", openSettings);
  $("#btn-close-settings").addEventListener("click", () => {
    settingsModal.classList.add("hidden");
  });
  $("#btn-save-settings").addEventListener("click", saveSettings);
  $("#btn-clear-minutaia").addEventListener("click", () => {
    if (confirm("Remover credenciais do MinutaIA e desconectar a sessao atual?")) {
      clearMinutaiaCredentialsAction();
    }
  });

  // Click no indicador MinutaIA abre o modal de configuracoes
  if (minutaiaIndicator) {
    minutaiaIndicator.addEventListener("click", openSettings);
  }

  // File upload (click only — drop-zone now is a simple link)
  const fileInput = $("#file-input");
  fileInput.addEventListener("change", () => {
    handleFileUpload(fileInput.files);
    fileInput.value = "";
  });

  // Modelos - texto manual
  $("#btn-modelo-texto").addEventListener("click", () => {
    $("#modelo-texto-modal").classList.toggle("hidden");
  });
  $("#btn-cancel-modelo").addEventListener("click", () => {
    $("#modelo-texto-modal").classList.add("hidden");
  });
  $("#btn-add-modelo").addEventListener("click", () => {
    const titulo = $("#modelo-titulo").value.trim();
    const conteudo = $("#modelo-conteudo").value.trim();
    if (!conteudo) return;
    userModels.push({
      title: titulo || `Modelo ${userModels.length + 1}`,
      content: conteudo,
      selected: true,
    });
    renderModelos();
    $("#modelo-titulo").value = "";
    $("#modelo-conteudo").value = "";
    $("#modelo-texto-modal").classList.add("hidden");
  });

  // Modelos - file upload
  $("#file-modelo").addEventListener("change", async (e) => {
    const file = e.target.files[0];
    if (!file) return;

    if (file.name.endsWith(".txt")) {
      const text = await file.text();
      userModels.push({ title: file.name, content: text, selected: true });
      renderModelos();
    } else if (file.name.endsWith(".pdf")) {
      try {
        showBanner(`Extraindo texto de ${file.name}...`, "loading");
        const buffer = await file.arrayBuffer();
        const result = await extractText(buffer);
        userModels.push({ title: file.name, content: result.content, selected: true });
        renderModelos();
        hideBanner();
      } catch (err) {
        showBanner(`Erro: ${err.message}`, "error");
      }
    }
    e.target.value = "";
  });

  // Historico refresh
  // (historico removido — sem btn-refresh-hist)
}

// ── Boot ────────────────────────────────────────────────────────────────

init().catch(e => {
  console.error("[panel] Erro na inicializacao:", e);
  showBanner(`Erro: ${e.message}`, "error");
});
