/**
 * Tickets Detail Panel — abas Resumo | Ao vivo | Funil + próxima acção contextual (P1)
 */
const TicketsDetailPanel = {
  activeTab: 'resumo',
  lastTicketId: null,
  mirrorTimer: null,
  mirrorSessionId: null,
  _drawerOpen: false,
  _escHandler: null,

  isOpen() {
    return this._drawerOpen;
  },

  getDrawerEls() {
    return {
      drawer: document.getElementById('ticket-drawer'),
      body: document.getElementById('ticket-drawer-body'),
      title: document.getElementById('ticket-drawer-title'),
    };
  },

  bindDrawerClose() {
    const { drawer } = this.getDrawerEls();
    if (!drawer || drawer.dataset.boundClose) return;
    drawer.dataset.boundClose = '1';
    drawer.querySelectorAll('[data-close-ticket-drawer]').forEach((el) => {
      el.addEventListener('click', () => this.closeDrawer());
    });
    this._escHandler = (ev) => {
      if (ev.key === 'Escape' && this._drawerOpen) this.closeDrawer();
    };
    document.addEventListener('keydown', this._escHandler);
  },

  openDrawer(ticketId) {
    const { drawer, body, title } = this.getDrawerEls();
    if (!drawer || !body) {
      console.warn('[TicketsDetailPanel] Modal ASM indisponível (#ticket-drawer)');
      return Promise.resolve();
    }
    this.bindDrawerClose();
    this._drawerOpen = true;
    drawer.classList.remove('hidden');
    drawer.setAttribute('aria-hidden', 'false');
    document.body.classList.add('ticket-drawer-open');
    if (title) title.textContent = `Ticket #${ticketId}`;
    return this.render(ticketId, body);
  },

  closeDrawer() {
    const { drawer } = this.getDrawerEls();
    this.stopMirrorPoll();
    this._drawerOpen = false;
    if (drawer) {
      drawer.classList.add('hidden');
      drawer.setAttribute('aria-hidden', 'true');
    }
    document.body.classList.remove('ticket-drawer-open');
  },

  stopMirrorPoll() {
    if (this.mirrorTimer) {
      clearInterval(this.mirrorTimer);
      this.mirrorTimer = null;
    }
    this.mirrorSessionId = null;
  },

  parseUiState(presence, uiState) {
    if (uiState && typeof uiState === 'object' && Object.keys(uiState).length) return uiState;
    if (presence?.ui_state) {
      try { return JSON.parse(presence.ui_state); } catch { return {}; }
    }
    return {};
  },

  mirrorHtml(observer) {
    if (!observer) {
      return '<p class="loading">Carregando espelho do wizard…</p>';
    }
    if (observer.is_assisting) {
      return '<p class="ticket-mirror-hint">ASM ativo — o cliente está pausado. Use <strong>Reabrir wizard ASM</strong> para continuar no modo técnico.</p>';
    }
    const ui = this.parseUiState(observer.presence, observer.ui_state);
    const step = observer.step_label || ui.step_label || observer.presence?.wizard_step || observer.funnel_stage || '—';
    const domain = observer.domain || ui.domain || '—';
    const errRaw = observer.client_error || ui.error;
    const err = errRaw && (observer.is_assisting || !String(errRaw).includes('controle interno do suporte'))
      ? errRaw
      : null;
    const modals = observer.modals || ui.modals || {};
    const modalLines = [];
    if (modals.support) modalLines.push('Modal <strong>Ajuda do Suporte</strong> aberto');
    if (modals.dns) modalLines.push('Modal <strong>DNS</strong> aberto');
    if (modals.dns_advanced) modalLines.push('Modal <strong>DNS avançado</strong> aberto');
    const activity = (observer.activity_log || []).slice(-12).map((e) => {
      const lvl = (e.level || 'info').toLowerCase();
      return `<li class="ticket-mirror-log ticket-mirror-log--${esc(lvl)}"><time>${esc((e.ts || e.created_at || '').slice(11, 19) || '—')}</time> ${esc(e.message || e.msg || '')}</li>`;
    }).join('');
    const infraPending = (observer.infra_status?.steps || []).filter((s) => !s.ok).slice(0, 4)
      .map((s) => esc(s.label || s.id)).join(' · ');
    return `
      <div class="ticket-mirror">
        <p class="ticket-mirror-lead">O técnico lê aqui o mesmo contexto do cliente <strong>antes</strong> de assumir a sessão.</p>
        <div class="ticket-mirror-screen">
          <div class="ticket-mirror-screen__bar">
            <span class="ticket-signal ticket-signal--live is-live"><i aria-hidden="true"></i>Cliente no wizard</span>
            ${observer.presence?.wizard_step || step !== '—' ? `<span class="ticket-mirror-step">${esc(step)}</span>` : ''}
          </div>
          <dl class="kv kv--compact ticket-mirror-kv">
            <dt>Passo</dt><dd><strong>${esc(step)}</strong></dd>
            <dt>Domínio</dt><dd>${esc(domain)}</dd>
            ${observer.wizard_ticket_id ? `<dt>Chamado wizard</dt><dd><code class="session-hash">${esc(observer.wizard_ticket_id)}</code></dd>` : ''}
            ${observer.client_note ? `<dt>Nota do cliente</dt><dd>${esc(observer.client_note)}</dd>` : ''}
          </dl>
          ${err ? `<div class="ticket-mirror-error" role="alert"><strong>Erro na tela do cliente</strong><p>${esc(err)}</p></div>` : ''}
          ${modalLines.length ? `<div class="ticket-mirror-modals">${modalLines.join(' · ')}</div>` : ''}
          ${infraPending ? `<p class="ticket-mirror-infra"><span>Infra pendente:</span> ${infraPending}</p>` : ''}
          <div class="ticket-mirror-terminal">
            <div class="ticket-mirror-terminal__head">Terminal / activity log (cliente)</div>
            <ol class="ticket-mirror-log-list">${activity || '<li class="ticket-meta">Sem linhas recentes</li>'}</ol>
          </div>
        </div>
        <p class="ticket-meta ticket-mirror-updated">Atualizado ${fmtDate(observer.presence?.last_seen_at || new Date().toISOString())}</p>
      </div>`;
  },

  async fetchObserverView(sessionId) {
    return api(`/v1/assist/sessions/${encodeURIComponent(sessionId)}/observer-view`);
  },

  async refreshMirrorPane(detailEl, sessionId) {
    const pane = detailEl.querySelector('[data-ticket-pane="espelho"]');
    if (!pane || pane.hidden) return;
    try {
      const observer = await this.fetchObserverView(sessionId);
      pane.innerHTML = this.mirrorHtml(observer);
    } catch (e) {
      pane.innerHTML = `<p class="loading">Espelho indisponível: ${esc(e.message)}</p>`;
    }
  },

  startMirrorPoll(detailEl, sessionId) {
    this.stopMirrorPoll();
    if (!sessionId) return;
    this.mirrorSessionId = sessionId;
    const tick = () => this.refreshMirrorPane(detailEl, sessionId);
    tick();
    this.mirrorTimer = setInterval(tick, 4000);
  },

  espelhoPaneHtml() {
    return `
      <div class="ticket-detail-pane" data-ticket-pane="espelho"${this.activeTab !== 'espelho' ? ' hidden' : ''}>
        <p class="loading">Carregando espelho do wizard…</p>
      </div>`;
  },

  computeNextAction(t, assistMeta, carbonioBlock) {
    const enriched = window.TicketsWorkspace?.enrichTicket
      ? TicketsWorkspace.enrichTicket(t)
      : t;
    if (carbonioBlock?.status === 'pending') {
      return {
        tone: 'warn',
        icon: '🔒',
        title: 'Bloqueio Carbonio',
        text: 'Remover conta órfã para o cliente repetir o passo',
        cta: 'scroll-carbonio',
      };
    }
    const assistStatus = normalizeAssistStatus(assistMeta?.assist_status || assistMeta?.ticket_status || t.status);
    if (assistStatus === 'assisting' && typeof canAssist === 'function' && canAssist()) {
      return {
        tone: 'brand',
        icon: '🖥️',
        title: 'ASM ativo',
        text: 'Fechou o wizard por engano? Reabra a sessão sem devolver ao cliente',
        cta: 'resume-wizard',
      };
    }
    if (enriched._live && typeof canAssist === 'function' && canAssist()
      && assistMeta?.can_escalate && assistStatus !== 'assisting') {
      return {
        tone: 'live',
        icon: '🟢',
        title: 'Cliente online',
        text: enriched._livePath
          ? `Em ${enriched._livePath} — abra Espelho cliente e depois assuma`
          : 'Abra a aba Espelho cliente para ver a mesma tela antes de assumir',
        cta: 'takeover',
      };
    }
    if (enriched._stale) {
      return {
        tone: 'stale',
        icon: '⏸',
        title: 'Sessão parada',
        text: `Sem progresso há ~${enriched._idleHours}h — escalar ou contactar`,
        cta: 'escalate',
      };
    }
    if (enriched._unassigned && enriched.status === 'open') {
      return {
        tone: 'info',
        icon: '👤',
        title: 'Sem dono',
        text: 'Ticket aberto sem técnico atribuído',
        cta: 'takeover',
      };
    }
    if (enriched._billing) {
      return {
        tone: 'billing',
        icon: '💳',
        title: 'Billing pendente',
        text: 'Validar pagamento antes de prosseguir onboarding',
        cta: null,
      };
    }
    if (enriched._wazuh && (enriched.severity == null || enriched.severity >= 10)) {
      return {
        tone: 'danger',
        icon: '⚠️',
        title: 'Alerta Wazuh',
        text: 'Investigar evento de segurança',
        cta: null,
      };
    }
    if (enriched.status === 'escalated') {
      return {
        tone: 'danger',
        icon: '🚨',
        title: 'Escalado',
        text: 'Prioridade operacional — assumir ou resolver',
        cta: 'takeover',
      };
    }
    return null;
  },

  nextActionHtml(action) {
    if (!action) return '';
    const cta = action.cta === 'takeover'
      ? '<button type="button" class="btn btn-primary btn-sm" data-next-action="takeover">Assumir</button>'
      : action.cta === 'resume-wizard'
        ? '<button type="button" class="btn btn-primary btn-sm" data-next-action="resume-wizard">Reabrir wizard</button>'
      : action.cta === 'escalate'
        ? '<button type="button" class="btn btn-ghost btn-sm" data-next-action="escalate">Escalar</button>'
        : action.cta === 'scroll-carbonio'
          ? '<button type="button" class="btn btn-primary btn-sm" data-next-action="scroll-carbonio">Resolver</button>'
          : '';
    return `
      <div class="ticket-next-action ticket-next-action--${action.tone}">
        <span class="ticket-next-action-icon" aria-hidden="true">${action.icon}</span>
        <div class="ticket-next-action-body">
          <strong>${esc(action.title)}</strong>
          <span>${esc(action.text)}</span>
        </div>
        ${cta ? `<div class="ticket-next-action-cta">${cta}</div>` : ''}
      </div>`;
  },

  tabsHtml({ t, sessionId, hasLive, hasFunil, hasEspelho }) {
    const tabs = [
      { id: 'resumo', label: 'Resumo' },
    ];
    if (hasEspelho) tabs.push({ id: 'espelho', label: 'Espelho cliente' });
    if (hasLive) tabs.push({ id: 'live', label: 'Ao vivo' });
    if (hasFunil) tabs.push({ id: 'funil', label: 'Funil' });
    if (!tabs.some((x) => x.id === this.activeTab)) this.activeTab = 'resumo';
    return `
      <nav class="ticket-detail-tabs" role="tablist">
        ${tabs.map((tab) => `
          <button type="button" role="tab"
            class="ticket-detail-tab${this.activeTab === tab.id ? ' active' : ''}"
            data-ticket-tab="${tab.id}"
            aria-selected="${this.activeTab === tab.id}">
            ${esc(tab.label)}
          </button>`).join('')}
      </nav>`;
  },

  resumoHtml(t, { sessionId, assistMeta, carbonioBlock }) {
    const closeStatuses = ['open', 'escalated', 'assisting', 'resolved'];
    const funnelKv = typeof ticketFunnelKvHtml === 'function'
      ? ticketFunnelKvHtml(t)
      : `<dt>Evento</dt><dd>${esc(t.event || '—')}</dd>`;
    return `
      <div class="ticket-detail-pane" data-ticket-pane="resumo"${this.activeTab !== 'resumo' ? ' hidden' : ''}>
        <div class="ticket-detail-layout">
          <section class="ticket-detail-section">
            <h4>Identificação</h4>
            <dl class="kv kv--compact kv--indented">
              <dt>Domínio / Agente</dt><dd>${esc(t.domain || t.agent || '—')}</dd>
              <dt>E-mail</dt><dd>${esc(t.email || '—')}</dd>
              ${funnelKv}
              ${t.description ? `<dt>Descrição</dt><dd>${esc(t.description)}</dd>` : ''}
              ${t.desk_message ? `<dt>Nota Desk</dt><dd>${esc(t.desk_message)}</dd>` : ''}
              <dt>Sessão / Alert ID</dt><dd><code>${esc(t.session_id || '—')}</code></dd>
              ${t.wizard_ticket_id ? `<dt>Chamado wizard</dt><dd><code class="session-hash">${esc(t.wizard_ticket_id)}</code></dd>` : ''}
              ${t.wizard_client_note ? `<dt>Nota cliente</dt><dd>${esc(t.wizard_client_note)}</dd>` : ''}
            </dl>
          </section>
          <section class="ticket-detail-section">
            <h4>Estado &amp; Operação</h4>
            <dl class="kv kv--compact kv--indented">
              <dt>Origem</dt><dd>${sourceBadge(t.source)}</dd>
              <dt>Status</dt><dd><span class="badge ${t.status}">${esc(statusLabel(t.status))}</span></dd>
              ${t.assigned_to ? `<dt>Atribuído</dt><dd>${esc(t.assigned_to)}</dd>` : ''}
              ${t.assisted_by ? `<dt>Assistido por</dt><dd>${esc(t.assisted_by)}</dd>` : ''}
              ${t.client_paused ? '<dt>Cliente</dt><dd><span class="badge assisting">pausado</span></dd>' : ''}
              ${t.ready_for_ops ? '<dt>Ops</dt><dd><span class="badge ok">ready for ops</span></dd>' : ''}
              ${t.severity != null ? `<dt>Severidade</dt><dd>${severityBadge(t.severity)}</dd>` : ''}
              ${t.rule_id ? `<dt>Regra</dt><dd>${esc(t.rule_id)}</dd>` : ''}
              ${t.registration_role ? `<dt>Perfil</dt><dd>${esc(roleLabel(t.registration_role))}</dd>` : ''}
              ${t.activation_url ? `<dt>Ativar conta</dt><dd><a class="btn btn-primary btn-sm" href="${esc(t.activation_url)}" target="_blank" rel="noopener">Abrir link</a></dd>` : ''}
              <dt>Verificado</dt><dd>${t.account_verified ? 'Sim' : 'Não'}</dd>
              <dt>Revisão</dt><dd>${t.needs_review ? 'Necessária' : 'Não'}</dd>
              <dt>Criado</dt><dd>${fmtDate(t.created_at)}</dd>
            </dl>
          </section>
        </div>
        ${sessionId && t.source === 'vm112-onboard' ? `
          <div class="ticket-detail-layout ticket-detail-layout--assist">
            <section class="ticket-detail-section ticket-detail-section--wide">
              ${assistActionsHtml(sessionId, {
                can_escalate: assistMeta?.can_escalate,
                assist_status: assistMeta?.assist_status || assistMeta?.ticket_status,
                ticket_status: assistMeta?.ticket_status || t.status,
                client_paused: assistMeta?.ticket?.client_paused ?? t.client_paused,
                assisted_by: assistMeta?.assisted_by,
                actions: assistMeta?.actions,
              }, assistMeta?._console || {})}
            </section>
          </div>` : ''}
        ${carbonioBlock ? `<div id="ticket-carbonio-block">${carbonioBlockPanelHtml(carbonioBlock)}</div>` : ''}
        <div class="ticket-detail-footer-actions">
          ${typeof canPatchTickets === 'function' && canPatchTickets()
            ? (closeStatuses.includes(t.status)
              ? '<button type="button" class="btn btn-primary" data-action="close">Fechar ticket</button>'
              : '<button type="button" class="btn btn-ghost" data-action="open">Reabrir ticket</button>')
            : ''}
        </div>
        <details class="ticket-payload-details">
          <summary>Payload técnico</summary>
          <pre class="raw">${esc(JSON.stringify(t.payload, null, 2))}</pre>
        </details>
      </div>`;
  },

  livePaneHtml(sessionId) {
    const enriched = window.TicketsWorkspace?.context?.liveBySession?.[sessionId];
    return `
      <div class="ticket-detail-pane" data-ticket-pane="live"${this.activeTab !== 'live' ? ' hidden' : ''}>
        ${enriched ? `
          <div class="ticket-live-presence-card">
            <span class="ticket-signal ticket-signal--live is-live"><i aria-hidden="true"></i>LIVE</span>
            <dl class="kv kv--compact">
              <dt>Path</dt><dd><code>${esc(enriched.path || '—')}</code></dd>
              <dt>Passo wizard</dt><dd>${esc(enriched.wizard_step || '—')}</dd>
              <dt>IP</dt><dd>${esc(enriched.ip || '—')}</dd>
              <dt>Último sinal</dt><dd>${fmtDate(enriched.last_seen_at || enriched.updated_at)}</dd>
            </dl>
          </div>` : '<p class="ticket-meta">Cliente offline neste momento.</p>'}
        <div id="ticket-detail-live-trail"></div>
        <button type="button" class="btn btn-ghost btn-sm" data-open-live-trail="${esc(sessionId)}">Trail completo (modal)</button>
      </div>`;
  },

  funilPaneHtml(timeline, timing) {
    return `
      <div class="ticket-detail-pane" data-ticket-pane="funil"${this.activeTab !== 'funil' ? ' hidden' : ''}>
        ${timeline?.length
          ? `${phaseTimingCardHtml(timing, timeline)}${timelineHtml(timeline, timing, { compact: false })}`
          : '<p class="ticket-meta">Sem eventos de funil para esta sessão.</p>'}
      </div>`;
  },

  bindTabs(detailEl) {
    detailEl.querySelectorAll('[data-ticket-tab]').forEach((btn) => {
      btn.addEventListener('click', () => {
        this.activeTab = btn.dataset.ticketTab;
        detailEl.querySelectorAll('[data-ticket-tab]').forEach((b) => {
          b.classList.toggle('active', b === btn);
          b.setAttribute('aria-selected', b === btn ? 'true' : 'false');
        });
        detailEl.querySelectorAll('[data-ticket-pane]').forEach((pane) => {
          pane.hidden = pane.dataset.ticketPane !== this.activeTab;
        });
        if (this.activeTab === 'live') {
          const sid = detailEl.dataset.sessionId;
          const trail = detailEl.querySelector('#ticket-detail-live-trail');
          if (sid && trail && window.DeskLive?.renderNavigationTab) {
            DeskLive.renderNavigationTab(sid, trail);
          }
        }
        if (this.activeTab === 'espelho') {
          const sid = detailEl.dataset.sessionId;
          if (sid) this.startMirrorPoll(detailEl, sid);
        } else {
          this.stopMirrorPoll();
        }
        if (this.activeTab === 'funil') bindLiveTimingClock(detailEl);
      });
    });
  },

  bindNextActions(detailEl, sessionId) {
    detailEl.querySelector('[data-next-action="takeover"]')?.addEventListener('click', async (e) => {
      const btn = e.currentTarget;
      btn.disabled = true;
      try {
        await runAssistAction('takeover', sessionId);
        await renderTickets();
        if (typeof refreshTicketDetailView === 'function') await refreshTicketDetailView();
      } catch (err) {
        alert(err.message || 'Falha ao assumir sessão');
      } finally {
        btn.disabled = false;
      }
    });
    detailEl.querySelector('[data-next-action="resume-wizard"]')?.addEventListener('click', async (e) => {
      const btn = e.currentTarget;
      btn.disabled = true;
      try {
        await runAssistAction('resume-wizard', sessionId);
        await renderTickets();
        if (typeof refreshTicketDetailView === 'function') await refreshTicketDetailView();
      } catch (err) {
        alert(err.message || 'Falha ao reabrir wizard ASM');
      } finally {
        btn.disabled = false;
      }
    });
    detailEl.querySelector('[data-next-action="escalate"]')?.addEventListener('click', async (e) => {
      const btn = e.currentTarget;
      btn.disabled = true;
      try {
        await runAssistAction('escalate', sessionId);
        await renderTickets();
        if (typeof refreshTicketDetailView === 'function') await refreshTicketDetailView();
      } catch (err) {
        alert(err.message || 'Falha ao escalar');
      } finally {
        btn.disabled = false;
      }
    });
    detailEl.querySelector('[data-next-action="scroll-carbonio"]')?.addEventListener('click', () => {
      this.activeTab = 'resumo';
      detailEl.querySelector('[data-ticket-tab="resumo"]')?.click();
      detailEl.querySelector('#ticket-carbonio-block')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
    });
    detailEl.querySelector('[data-open-live-trail]')?.addEventListener('click', (e) => {
      if (window.DeskLive?.openTrail) DeskLive.openTrail(e.currentTarget.dataset.openLiveTrail);
    });
  },

  async render(ticketId, detailEl) {
    if (!ticketId || !detailEl) return;
    this.stopMirrorPoll();
    const isFreshTicket = this.lastTicketId !== ticketId;
    if (isFreshTicket) {
      this.activeTab = 'resumo';
      this.lastTicketId = ticketId;
    }
    detailEl.innerHTML = '<p class="loading">Carregando…</p>';
    try {
      const t = await api(`/v1/desk/tickets/${ticketId}`);
      const sessionId = t.session_id || state.selectedSessionId;
      const assistMeta = sessionId && t.source === 'vm112-onboard'
        ? await loadAssistMeta(sessionId)
        : null;
      if (sessionId) state.selectedSessionId = sessionId;

      let carbonioBlock = null;
      if (t.source === 'vm112-onboard' && window.DeskModules?.isEnabled('carbonio-release')) {
        try {
          const byTicket = await api(`/v1/carbonio-blocks?ticket_id=${t.id}&status=pending&limit=1`);
          carbonioBlock = byTicket.blocks?.[0] || null;
          if (!carbonioBlock && sessionId) {
            const bySession = await api(`/v1/carbonio-blocks?session_id=${encodeURIComponent(sessionId)}&status=pending&limit=1`);
            carbonioBlock = bySession.blocks?.[0] || null;
          }
        } catch {
          carbonioBlock = null;
        }
      }

      const timeline = assistMeta?.timeline?.length
        ? assistMeta.timeline
        : (t.timeline || t.related_events || []);
      const timing = assistMeta?.timing || t.timing;
      const hasLive = Boolean(sessionId && t.source === 'vm112-onboard' && window.DeskLive?.enabled());
      const hasEspelho = Boolean(sessionId && t.source === 'vm112-onboard');
      const hasFunil = timeline.length > 0;
      const assistStatus = normalizeAssistStatus(assistMeta?.assist_status || assistMeta?.ticket_status || t.status);
      if (isFreshTicket && hasEspelho && hasLive && assistStatus !== 'assisting') {
        this.activeTab = 'espelho';
      }
      const nextAction = this.computeNextAction(t, assistMeta, carbonioBlock);

      detailEl.innerHTML = `
        <div class="ticket-detail-shell" data-session-id="${esc(sessionId || '')}">
          ${detailEl.id !== 'ticket-drawer-body' ? `
          <div class="ticket-detail-header">
            <div>
              <h3 style="margin:0">Ticket #${t.id}${t.wizard_ticket_id ? ` · <code class="session-hash">${esc(t.wizard_ticket_id)}</code>` : ''}</h3>
              <p class="ticket-meta">${esc(t.domain || t.subject || t.agent || '')}</p>
            </div>
            <span class="badge ${t.status}">${esc(statusLabel(t.status))}</span>
          </div>` : `
          <div class="ticket-modal-meta">
            <span class="badge ${t.status}">${esc(statusLabel(t.status))}</span>
            ${t.source === 'vm112-onboard' ? '<span class="ticket-modal-asm-badge">Onboard · ASM</span>' : ''}
            ${t.client_paused ? '<span class="badge assisting">Cliente pausado</span>' : ''}
            ${t.assisted_by ? `<span class="ticket-meta">Técnico: <strong>${esc(t.assisted_by)}</strong></span>` : ''}
          </div>`}
          ${this.nextActionHtml(nextAction)}
          ${this.tabsHtml({ t, sessionId, hasLive, hasFunil, hasEspelho })}
          ${this.resumoHtml(t, { sessionId, assistMeta, carbonioBlock })}
          ${hasEspelho ? this.espelhoPaneHtml() : ''}
          ${hasLive ? this.livePaneHtml(sessionId) : ''}
          ${hasFunil ? this.funilPaneHtml(timeline, timing) : ''}
        </div>`;

      const drawerTitle = document.getElementById('ticket-drawer-title');
      if (drawerTitle && detailEl.id === 'ticket-drawer-body') {
        drawerTitle.textContent = `Ticket #${t.id}${t.domain ? ` · ${t.domain}` : ''}`;
      }

      this.bindTabs(detailEl);
      this.bindNextActions(detailEl, sessionId);
      if (sessionId && t.source === 'vm112-onboard') bindAssistActions(detailEl, sessionId);
      bindCarbonioResolveForms(detailEl);
      bindLiveTimingClock(detailEl);
      if (this.activeTab === 'espelho' && sessionId) {
        this.startMirrorPoll(detailEl, sessionId);
      }
      if (this.activeTab === 'live' && hasLive) {
        const trail = detailEl.querySelector('#ticket-detail-live-trail');
        if (trail) await DeskLive.renderNavigationTab(sessionId, trail);
      }
      detailEl.querySelector('[data-action="close"]')?.addEventListener('click', () => updateTicketStatus('closed'));
      detailEl.querySelector('[data-action="open"]')?.addEventListener('click', () => updateTicketStatus('open'));
    } catch (e) {
      detailEl.innerHTML = `<div class="card"><p class="loading">Erro: ${esc(e.message)}</p></div>`;
    }
  },
};

window.TicketsDetailPanel = TicketsDetailPanel;
