<script>
/* ============================================================================
 * JEV Box — análise de conversa via JEV (TypeSafe) dentro do Chatwoot oficial
 * ----------------------------------------------------------------------------
 * Injeta um box no painel lateral do ticket (logo abaixo dos boxes nativos:
 * Ações da Conversa, Macros, etc.), com um botão "Analisar conversa" que puxa
 * as mensagens e devolve uma NOTA multi-métrica (qualidade, satisfação,
 * temperatura do lead, risco de churn, categoria, precisa-humano).
 *
 * • Sem backend/proxy: chama o OpenRouter (typesafe/jev-router) direto do browser.
 *   ⚠️ A OPENROUTER_KEY abaixo fica VISÍVEL no código. Use uma key COM LIMITE de
 *      gasto no OpenRouter. É a key do próprio inscrito, na instância dele.
 * • Self-hosted apenas (no Chatwoot Cloud não dá pra injetar script).
 *
 * INSTALAÇÃO (self-hosted): injete este arquivo no HTML do dashboard, ex. via
 * nginx `sub_filter` (README) ou userscript. Depois preencha o CONFIG abaixo.
 * ========================================================================== */
(function () {
  'use strict';

  // ======================== CONFIG (edite aqui) ============================
  const CONFIG = {
    OPENROUTER_KEY: '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',   // key OpenRouter (com limite!)
    MODEL: 'typesafe/jev-router',
    BOX_TITLE: 'Análise JEV',
    BUTTON_LABEL: 'Analisar conversa',
    MAX_MESSAGES: 30,           // quantas mensagens recentes enviar
    RETRIES: 3,                 // re-tentativas em 502/503/504 (JEV instável)
    // O que a nota mede (o modelo devolve exatamente estas chaves em JSON):
    METRICS: [
      { key: 'nota_atendimento', label: 'Nota do atendimento', type: 'score0a10' },
      { key: 'satisfacao',       label: 'Satisfação do cliente', type: 'score0a10' },
      { key: 'temperatura_lead', label: 'Temperatura do lead',  type: 'texto',  opcoes: 'frio|morno|quente' },
      { key: 'chance_venda',     label: 'Chance de fechar venda', type: 'texto', opcoes: 'baixa|media|alta' },
      { key: 'categoria',        label: 'Categoria',            type: 'texto',  opcoes: 'financeiro|suporte|comercial|outro' },
      { key: 'precisa_humano',   label: 'Precisa de humano?',   type: 'boolean' },
      { key: 'resumo',           label: 'Resumo',               type: 'texto' },
    ],
  };
  // ========================================================================

  const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions';
  const BOX_ID = 'jev-box-root';

  // ---- auth do Chatwoot (devise-token-auth): lê do cookie cw_d_session_info ----
  function authHeaders() {
    try {
      const raw = document.cookie.split('; ').find(c => c.startsWith('cw_d_session_info='));
      if (raw) {
        const info = JSON.parse(decodeURIComponent(raw.split('=').slice(1).join('=')));
        if (info['access-token']) {
          return { 'access-token': info['access-token'], client: info.client, uid: info.uid };
        }
      }
    } catch (e) { /* ignore */ }
    // fallback: localStorage
    try {
      const at = localStorage.getItem('access-token') || localStorage.getItem('cw_access_token');
      if (at) return { 'access-token': at, client: localStorage.getItem('client'), uid: localStorage.getItem('uid') };
    } catch (e) { /* ignore */ }
    return null;
  }

  function ids() {
    const m = location.pathname.match(/\/accounts\/(\d+)\/(?:conversations|custom_view\/\d+\/conversations)\/(\d+)/) ||
              location.pathname.match(/\/accounts\/(\d+)\/.*\/(\d+)/);
    return m ? { account: m[1], conversation: m[2] } : null;
  }

  // ---- puxa as mensagens da conversa via API do Chatwoot ----
  async function fetchConversation(acc, conv) {
    const h = authHeaders();
    if (!h) throw new Error('Sem sessão do Chatwoot (recarregue e logue).');
    const res = await fetch(`/api/v1/accounts/${acc}/conversations/${conv}/messages`, {
      headers: { ...h, 'Content-Type': 'application/json' },
    });
    if (!res.ok) throw new Error(`API Chatwoot ${res.status}`);
    const data = await res.json();
    const msgs = (data.payload || data.data || data || [])
      .filter(m => m && typeof m.content === 'string' && m.content.trim() && m.message_type !== 2) // 2 = activity
      .slice(-CONFIG.MAX_MESSAGES)
      .map(m => `${m.message_type === 1 ? 'Atendente' : 'Cliente'}: ${m.content.trim()}`);
    return msgs.join('\n');
  }

  // ---- monta o prompt pedindo TODAS as métricas em JSON ----
  function buildMessages(texto) {
    const linhas = CONFIG.METRICS.map(m => {
      let regra = m.type === 'score0a10' ? 'número inteiro 0 a 10'
                : m.type === 'boolean' ? 'true ou false'
                : m.opcoes ? `um de: ${m.opcoes}`
                : 'texto curto';
      return `- "${m.key}": ${m.label} (${regra})`;
    }).join('\n');
    const sys = 'Você avalia uma conversa de atendimento e responde ESTRITAMENTE com um ' +
      'objeto JSON válido (sem markdown, sem comentários) com EXATAMENTE estas chaves:\n' + linhas;
    return [{ role: 'system', content: sys }, { role: 'user', content: 'CONVERSA:\n' + texto }];
  }

  // ---- chama o OpenRouter (jev-router) com retry ----
  async function callJev(texto) {
    const body = JSON.stringify({ model: CONFIG.MODEL, messages: buildMessages(texto) });
    let last = '';
    for (let a = 1; a <= CONFIG.RETRIES; a++) {
      try {
        const res = await fetch(OPENROUTER_URL, {
          method: 'POST',
          headers: {
            Authorization: `Bearer ${CONFIG.OPENROUTER_KEY}`,
            'Content-Type': 'application/json',
            'HTTP-Referer': location.origin,
            'X-Title': 'Chatwoot JEV Box',
          },
          body,
        });
        if ([429, 502, 503, 504].includes(res.status) && a < CONFIG.RETRIES) {
          last = `JEV ${res.status}`; await sleep(500 * a); continue;
        }
        if (!res.ok) throw new Error(`OpenRouter ${res.status}`);
        const data = await res.json();
        const text = data?.choices?.[0]?.message?.content || '';
        const json = parseLoose(text);
        if (!json) throw new Error('Resposta não-JSON do JEV');
        return json;
      } catch (e) {
        last = e.message; if (a < CONFIG.RETRIES) await sleep(500 * a);
      }
    }
    throw new Error(last || 'Falha ao chamar o JEV');
  }

  const sleep = ms => new Promise(r => setTimeout(r, ms));
  function parseLoose(t) { try { const m = t.match(/\{[\s\S]*\}/); return m ? JSON.parse(m[0]) : null; } catch (e) { return null; } }

  // ---- container dos boxes do painel DIREITO da conversa (accordions) ----
  function boxesContainer() {
    return document.querySelector('.list-group .flex.flex-col.gap-3') ||
           document.querySelector('.list-group > div') ||
           (document.querySelector('.conversation--actions') || {}).parentElement || null;
  }

  // ícones +/− do chevron (iguais aos nativos do Chatwoot)
  const ICON_PLUS = '<svg width="24" height="24" fill="none" viewBox="0 0 24 24"><path d="M11.883 3.007 12 3a1 1 0 0 1 .993.883L13 4v7h7a1 1 0 0 1 .993.883L21 12a1 1 0 0 1-.883.993L20 13h-7v7a1 1 0 0 1-.883.993L12 21a1 1 0 0 1-.993-.883L11 20v-7H4a1 1 0 0 1-.993-.883L3 12a1 1 0 0 1 .883-.993L4 11h7V4a1 1 0 0 1 .883-.993L12 3l-.117.007Z" fill="currentColor"></path></svg>';
  const ICON_MINUS = '<svg width="24" height="24" fill="none" viewBox="0 0 24 24"><path d="M3.75 12a1 1 0 0 1 1-1h14.5a1 1 0 1 1 0 2H4.75a1 1 0 0 1-1-1Z" fill="currentColor"></path></svg>';
  let expanded = false;

  function ensureBox() {
    const where = ids();
    if (!where) { removeBox(); return; }
    if (document.getElementById(BOX_ID)) return; // já existe

    const container = boxesContainer();
    if (!container) return; // painel ainda não renderizou

    // Accordion IDÊNTICO aos boxes nativos (mesmas classes n-*: header bg-n-slate-2 +
    // outline-n-weak, corpo bg-n-solid-1 recolhível). Fica no FIM → abaixo dos nativos.
    const section = document.createElement('div');
    section.id = BOX_ID;
    section.setAttribute('data-draggable', 'false');
    section.innerHTML =
      '<div class="text-sm">' +
        '<button id="jev-toggle" class="flex items-center select-none w-full rounded-lg bg-n-slate-2 outline outline-1 outline-n-weak m-0 cursor-pointer justify-between py-2 px-4">' +
          '<div class="flex justify-between"><h5 class="text-n-slate-12 text-sm mb-0 py-0 pr-2 pl-0">🧠 ' + escapeHtml(CONFIG.BOX_TITLE) + '</h5></div>' +
          '<div class="flex flex-row"><div id="jev-chevron" class="flex justify-end w-3 cursor-pointer" style="color:rgba(var(--text-blue))">' + ICON_PLUS + '</div></div>' +
        '</button>' +
        '<div id="jev-body" class="outline outline-1 outline-n-weak rounded-b-lg overflow-hidden bg-n-solid-1 p-4" style="display:none;">' +
          '<button id="jev-run" style="width:100%;padding:8px 12px;border-radius:8px;border:1px solid var(--n-weak,rgba(127,127,127,.4));background:transparent;color:inherit;cursor:pointer;font-weight:600;">' + escapeHtml(CONFIG.BUTTON_LABEL) + '</button>' +
          '<div id="jev-result" style="margin-top:10px;font-size:13px;line-height:1.5;"></div>' +
        '</div>' +
      '</div>';
    container.insertBefore(section, container.firstElementChild); // PRIMEIRO box (topo)
    section.querySelector('#jev-toggle').addEventListener('click', function (e) { e.stopPropagation(); toggleBox(); });
    section.querySelector('#jev-run').addEventListener('click', onAnalyze);
  }

  // expande/recolhe igual ao nativo (arredonda cantos, troca +/−)
  function toggleBox() {
    const body = document.getElementById('jev-body');
    const chev = document.getElementById('jev-chevron');
    const btn = document.getElementById('jev-toggle');
    if (!body) return;
    expanded = !expanded;
    body.style.display = expanded ? 'block' : 'none';
    if (btn) { btn.classList.toggle('rounded-lg', !expanded); btn.classList.toggle('rounded-t-lg', expanded); }
    if (chev) chev.innerHTML = expanded ? ICON_MINUS : ICON_PLUS;
  }

  function removeBox() { const b = document.getElementById(BOX_ID); if (b) b.remove(); }

  async function onAnalyze() {
    const where = ids(); const out = document.getElementById('jev-result');
    const btn = document.getElementById('jev-run');
    if (!where || !out) return;
    btn.disabled = true; out.innerHTML = '<em>Analisando… (o JEV pode demorar/re-tentar)</em>';
    try {
      const texto = await fetchConversation(where.account, where.conversation);
      if (!texto) { out.innerHTML = '<em>Conversa sem mensagens de texto.</em>'; return; }
      const r = await callJev(texto);
      out.innerHTML = renderResult(r);
    } catch (e) {
      out.innerHTML = `<span style="color:#e11">Erro: ${escapeHtml(e.message)}</span>
        <div style="opacity:.7;margin-top:4px">Tente de novo — o JEV está em early-access e oscila.</div>`;
    } finally { btn.disabled = false; }
  }

  function renderResult(r) {
    const rows = CONFIG.METRICS.map(m => {
      let v = r[m.key];
      if (v === undefined || v === null || v === '') return '';
      if (m.type === 'boolean') v = (v === true || v === 'true' || v === 'sim') ? 'Sim' : 'Não';
      if (m.type === 'score0a10') v = `<strong>${v}</strong>/10`;
      else v = escapeHtml(String(v));
      return `<div style="display:flex;justify-content:space-between;gap:8px;padding:3px 0;border-top:1px solid rgba(127,127,127,.15)">
        <span style="opacity:.75">${escapeHtml(m.label)}</span><span>${v}</span></div>`;
    }).join('');
    return rows + `<div style="opacity:.5;font-size:11px;margin-top:6px">via JEV · ${new Date().toLocaleTimeString()}</div>`;
  }

  function escapeHtml(s) { return String(s).replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c])); }

  // ---- SPA: re-injeta ao navegar entre conversas ----
  let tick = null;
  function schedule() { clearTimeout(tick); tick = setTimeout(ensureBox, 400); }
  new MutationObserver(schedule).observe(document.body, { childList: true, subtree: true });
  window.addEventListener('popstate', schedule);
  schedule();
})();

</script>