/**
 * Tickets Workspace — P0 lista (8 KPIs + 3 sinais) · P1 filas · P2 KPI click + softRefresh
 * Arquitectura separada; app.js delega render aqui.
 */
const TicketsWorkspace = {
  context: null,
  searchQuery: '',
  queueFilter: null,
  _pageReady: false,
  _listFingerprint: '',

  QUEUE_CHIPS: [
    { key: 'live', label: 'Live agora', icon: '🟢' },
    { key: 'stale', label: 'Parados', icon: '⏸' },
    { key: 'unassigned', label: 'Sem dono', icon: '👤' },
    { key: 'billing', label: 'Billing', icon: '💳' },
    { key: 'wazuh', label: 'Wazuh', icon: '⚠️' },
    { key: 'escalated', label: 'Escalados', icon: '🚨' },
  ],

  async loadContext() {
    const user = typeof getUser === 'function' ? getUser() : null;
    const [presence, funnel, summary] = await Promise.all([
      window.DeskLive?.enabled()
        ? api('/v1/live/presence').catch(() => ({ sessions: [] }))
        : Promise.resolve({ sessions: [] }),
      api('/v1/onboard/funnel?window_hours=48').catch(() => ({ active_sessions: [] })),
      api('/v1/desk/summary').catch(() => ({})),
    ]);
    const liveBySession = {};
    for (const s of presence.sessions || []) {
      if (s.session_id) liveBySession[s.session_id] = s;
    }
    const funnelBySession = {};
    for (const s of funnel.active_sessions || []) {
      if (s.session_id) funnelBySession[s.session_id] = s;
    }
    this.context = {
      liveBySession,
      funnelBySession,
      staleHours: summary.onboard_stale_hours ?? 24,
      user,
    };
    return this.context;
  },

  stripEnrichment(t) {
    const out = { ...t };
    for (const k of Object.keys(out)) {
      if (k.startsWith('_')) delete out[k];
    }
    return out;
  },

  enrichTicket(t) {
    const ctx = this.context || { liveBySession: {}, funnelBySession: {}, staleHours: 24 };
    const sid = (t.session_id || '').trim();
    const live = sid ? ctx.liveBySession[sid] : null;
    const funnel = sid ? ctx.funnelBySession[sid] : null;
    const isActive = ['open', 'escalated', 'assisting', 'resolved'].includes(t.status);
    const lastAt = funnel?.last_event_at || t.created_at;
    let idleHours = 0;
    if (lastAt) {
      idleHours = (Date.now() - new Date(lastAt).getTime()) / 3600000;
    }
    const stale = funnel?.stale || (isActive && idleHours >= ctx.staleHours);
    const stage = funnel?.current_stage || t.lead_funnel_stage || t.event;
    return {
      ...t,
      _live: Boolean(live),
      _livePath: (live?.path && !String(live.path).startsWith('/api/')) ? live.path : (funnel?.current_path && !String(funnel.current_path).startsWith('/api/') ? funnel.current_path : null),
      _stage: stage,
      _stageLabel: typeof FUNNEL_LABELS !== 'undefined' ? (FUNNEL_LABELS[stage] || stage) : stage,
      _idleHours: Math.round(idleHours),
      _stale: stale && isActive,
      _unassigned: isActive && !t.assigned_to && !t.assisted_by,
      _billing: Boolean(t.billing_state) || (t.subject || '').includes('[billing'),
      _wazuh: t.source === 'wazuh' || t.event === 'wazuh.alert',
      _carbonioHint: (t.subject || '').toLowerCase().includes('carbonio')
        || (t.subject || '').toLowerCase().includes('account_exists'),
    };
  },

  computeIndicators(tickets) {
    const enriched = tickets.map((t) => this.enrichTicket(t));
    const active = enriched.filter((t) => ['open', 'escalated', 'assisting', 'resolved'].includes(t.status));
    return {
      open: active.filter((t) => t.status === 'open').length,
      assisting: enriched.filter((t) => t.status === 'assisting').length,
      escalated: enriched.filter((t) => t.status === 'escalated').length,
      live: enriched.filter((t) => t._live).length,
      unassigned: active.filter((t) => t._unassigned).length,
      stale: active.filter((t) => t._stale).length,
      billing: enriched.filter((t) => t._billing).length,
      wazuh: enriched.filter((t) => t._wazuh).length,
      total: enriched.length,
    };
  },

  indicatorsHtml(ind) {
    const items = [
      { key: 'open', label: 'Abertos', value: ind.open, tone: 'info' },
      { key: 'assisting', label: 'Assistindo', value: ind.assisting, tone: 'brand' },
      { key: 'escalated', label: 'Escalados', value: ind.escalated, tone: 'danger' },
      { key: 'live', label: 'Live agora', value: ind.live, tone: 'live' },
      { key: 'unassigned', label: 'Sem dono', value: ind.unassigned, tone: 'warn' },
      { key: 'stale', label: 'Parados', value: ind.stale, tone: 'muted' },
      { key: 'billing', label: 'Billing', value: ind.billing, tone: 'billing', icon: '💳' },
      { key: 'wazuh', label: 'Wazuh', value: ind.wazuh, tone: 'security', icon: '⚠️' },
    ];
    return `
      <div class="tickets-kpi-strip" role="group" aria-label="Indicadores da fila">
        ${items.map((it) => `
          <button type="button"
            class="tickets-kpi tickets-kpi--${it.tone}${this.queueFilter === it.key ? ' active' : ''}"
            data-ticket-kpi="${it.key}"
            title="Filtrar: ${esc(it.label)}">
            <span class="tickets-kpi-value">${it.icon && it.value ? `${it.icon} ` : ''}${it.value}</span>
            <span class="tickets-kpi-label">${esc(it.label)}</span>
          </button>`).join('')}
      </div>`;
  },

  queueChipsHtml() {
    return `
      <div class="tickets-queue-bar" role="group" aria-label="Filas inteligentes">
        <span class="tickets-queue-label">Filas:</span>
        ${this.QUEUE_CHIPS.map((c) => `
          <button type="button"
            class="tickets-queue-chip${this.queueFilter === c.key ? ' active' : ''}"
            data-ticket-queue="${c.key}">
            ${c.icon} ${esc(c.label)}
          </button>`).join('')}
        ${this.queueFilter ? '<button type="button" class="tickets-queue-clear" data-ticket-queue-clear">Limpar fila</button>' : ''}
      </div>`;
  },

  phaseSignal(t) {
    if (t._stale) return { text: `parado ${t._idleHours}h`, cls: 'stale' };
    if (t._stageLabel && t._stageLabel !== t.event) {
      const short = String(t._stageLabel).replace(/validado|aplicado|criada/gi, '').trim() || t._stageLabel;
      return { text: short.slice(0, 28), cls: 'phase' };
    }
    if (t.event) return { text: String(t.event).replace('onboarding.', '').replace('.', ' '), cls: 'phase' };
    return { text: '—', cls: 'muted' };
  },

  ticketCardHtml(t) {
    const phase = this.phaseSignal(t);
    const isOnboard = t.source === 'vm112-onboard' || t.event?.startsWith?.('onboarding');
    const title = t.event === 'wazuh.alert'
      ? esc(t.description || t.agent || t.subject)
      : t.domain
        ? esc(t.domain)
        : isOnboard
          ? `Onboarding · ${esc(t._stageLabel || 'VM112')}`
          : esc(t.subject || `Ticket #${t.id}`);
    const metaParts = [];
    metaParts.push(`#${t.id}`);
    if (t.wizard_ticket_id) metaParts.push(esc(t.wizard_ticket_id));
    if (t.session_id) metaParts.push(sessionHashHtml(t.session_id, { full: false }));
    if (t.email) metaParts.push(esc(t.email));
    if (t.assigned_to || t.assisted_by) metaParts.push(esc(t.assisted_by || t.assigned_to));
    metaParts.push(fmtDate(t.created_at));
    const icons = [
      t._billing ? '<span class="ticket-icon-chip" title="Billing">💳</span>' : '',
      t._carbonioHint ? '<span class="ticket-icon-chip" title="Carbonio">🔒</span>' : '',
      t._wazuh ? `<span class="ticket-icon-chip" title="Wazuh">${severityBadge(t.severity) || '⚠️'}</span>` : '',
      t.crm_track === 'lead' ? '<span class="ticket-icon-chip ticket-icon-chip--lead">LEAD</span>' : '',
    ].filter(Boolean).join('');
    const selected = state.selectedTicketId === t.id;
    return `
      <button type="button"
        class="ticket-card ticket-card--${t.status}${selected ? ' selected' : ''}${t._live ? ' ticket-card--live' : ''}"
        data-id="${t.id}"${t.session_id ? ` data-session="${esc(t.session_id)}"` : ''}
        data-live="${t._live ? '1' : '0'}" data-stale="${t._stale ? '1' : '0'}">
        <span class="ticket-card-rail ticket-card-rail--${t.status}" aria-hidden="true"></span>
        <span class="ticket-card-main">
          <span class="ticket-card-signals">
            <span class="ticket-signal ticket-signal--status ticket-signal--${t.status}">${esc(statusLabel(t.status))}</span>
            <span class="ticket-signal ticket-signal--live ${t._live ? 'is-live' : 'is-offline'}">
              <i aria-hidden="true"></i>${t._live ? 'LIVE' : 'offline'}</span>
            <span class="ticket-signal ticket-signal--phase ticket-signal--${phase.cls}">${esc(phase.text)}</span>
          </span>
          <span class="ticket-card-title">${title}</span>
          <span class="ticket-card-meta">${metaParts.join(' · ')}</span>
          ${t._live && t._livePath ? `<span class="ticket-card-livepath" data-live-path>${esc(t._livePath)}</span>` : ''}
          ${icons ? `<span class="ticket-card-icons">${icons}</span>` : ''}
        </span>
        <span class="ticket-card-aside">${sourceBadge(t.source)}</span>
      </button>`;
  },

  filterByQueue(tickets) {
    if (!this.queueFilter) return tickets;
    const rules = {
      open: (t) => t.status === 'open',
      assisting: (t) => t.status === 'assisting',
      escalated: (t) => t.status === 'escalated',
      live: (t) => t._live,
      unassigned: (t) => t._unassigned,
      stale: (t) => t._stale,
      billing: (t) => t._billing,
      wazuh: (t) => t._wazuh,
    };
    const fn = rules[this.queueFilter];
    return fn ? tickets.filter(fn) : tickets;
  },

  filterBySearch(tickets) {
    const raw = (this.searchQuery || '').trim();
    if (!raw) return tickets;
    const q = raw.toLowerCase();
    const ticketIdQuery = q.replace(/^ticket\s*#?/, '').replace(/^#/, '').trim();

    return tickets.filter((t) => {
      if (/^\d+$/.test(ticketIdQuery) && String(t.id) === ticketIdQuery) return true;
      const wiz = (t.wizard_ticket_id || '').toLowerCase();
      if (wiz && (wiz === q || wiz.includes(q))) return true;
      const liveIp = this.context?.liveBySession?.[t.session_id]?.client_ip;
      const hay = [
        t.id,
        `#${t.id}`,
        `ticket ${t.id}`,
        t.subject,
        t.domain,
        t.email,
        t.session_id,
        t.agent,
        t.description,
        t.assigned_to,
        t.assisted_by,
        t.wizard_ticket_id,
        liveIp,
      ].filter(Boolean).join(' ').toLowerCase();
      return hay.includes(q);
    });
  },

  applyFilters(tickets) {
    return this.filterBySearch(this.filterByQueue(tickets));
  },

  listFingerprint(tickets) {
    return tickets.map((t) => [
      t.id, t.status, t._live ? 1 : 0, t._stale ? 1 : 0, t._stage, t._idleHours, t._livePath || '',
    ].join(':')).join('|');
  },

  setQueueFilter(key) {
    this.queueFilter = this.queueFilter === key ? null : key;
    const bar = document.getElementById('tickets-queue-bar');
    if (bar) {
      bar.innerHTML = this.queueChipsHtml();
      this.bindQueueBar(bar);
    }
    this.syncQueueUi();
    this.renderListOnly();
  },

  syncQueueUi() {
    document.querySelectorAll('[data-ticket-kpi]').forEach((el) => {
      el.classList.toggle('active', el.dataset.ticketKpi === this.queueFilter);
    });
    document.querySelectorAll('[data-ticket-queue]').forEach((el) => {
      el.classList.toggle('active', el.dataset.ticketQueue === this.queueFilter);
    });
    const clearBtn = document.querySelector('[data-ticket-queue-clear]');
    if (clearBtn) clearBtn.hidden = !this.queueFilter;
  },

  bindKpiStrip(strip) {
    strip.querySelectorAll('[data-ticket-kpi]').forEach((el) => {
      el.addEventListener('click', () => this.setQueueFilter(el.dataset.ticketKpi));
    });
  },

  bindQueueBar(bar) {
    bar.querySelectorAll('[data-ticket-queue]').forEach((el) => {
      el.addEventListener('click', () => this.setQueueFilter(el.dataset.ticketQueue));
    });
    bar.querySelector('[data-ticket-queue-clear]')?.addEventListener('click', () => {
      this.queueFilter = null;
      this.syncQueueUi();
      this.renderListOnly();
    });
  },

  bindList(listEl) {
    listEl.querySelectorAll('.ticket-card').forEach((btn) => {
      btn.addEventListener('click', () => {
        state.selectedTicketId = Number(btn.dataset.id);
        state.selectedSessionId = btn.dataset.session || null;
        listEl.querySelectorAll('.ticket-card').forEach((r) => r.classList.remove('selected'));
        btn.classList.add('selected');
        if (window.TicketsDetailPanel) TicketsDetailPanel.render(state.selectedTicketId, document.getElementById('ticket-detail'));
        else if (typeof renderTicketDetail === 'function') renderTicketDetail();
      });
    });
  },

  mountSearchToolbar() {
    let bar = document.getElementById('tickets-search-bar');
    if (!bar) {
      const toolbar = document.querySelector('#view-tickets .toolbar');
      if (!toolbar) return;
      bar = document.createElement('div');
      bar.id = 'tickets-search-bar';
      bar.className = 'tickets-search-bar';
      bar.innerHTML = `
        <input type="search" id="tickets-search-input" class="tickets-search-input"
          placeholder="Buscar ticket #, domínio, e-mail, sessão, OB-…, IP…" autocomplete="off" />
        <span class="tickets-search-hint ticket-meta">Scan rápido · 3 sinais por card</span>`;
      toolbar.parentNode.insertBefore(bar, toolbar);
      bar.querySelector('#tickets-search-input')?.addEventListener('input', (e) => {
        this.searchQuery = e.target.value;
        if (state.view === 'tickets') this.renderListOnly();
      });
    }
  },

  mountQueueBar() {
    let bar = document.getElementById('tickets-queue-bar');
    if (!bar) {
      const view = document.getElementById('view-tickets');
      const toolbar = view?.querySelector('.toolbar');
      if (!toolbar) return;
      bar = document.createElement('div');
      bar.id = 'tickets-queue-bar';
      toolbar.parentNode.insertBefore(bar, toolbar.nextSibling);
    }
    bar.innerHTML = this.queueChipsHtml();
    this.bindQueueBar(bar);
  },

  updateKpiStrip(ind) {
    const strip = document.getElementById('tickets-kpi-strip');
    if (!strip) return;
    const map = {
      open: ind.open, assisting: ind.assisting, escalated: ind.escalated, live: ind.live,
      unassigned: ind.unassigned, stale: ind.stale, billing: ind.billing, wazuh: ind.wazuh,
    };
    strip.querySelectorAll('[data-ticket-kpi]').forEach((el) => {
      const key = el.dataset.ticketKpi;
      const val = map[key];
      if (val == null) return;
      const valueEl = el.querySelector('.tickets-kpi-value');
      if (valueEl) {
        const icon = (key === 'billing' && val) ? '💳 ' : (key === 'wazuh' && val) ? '⚠️ ' : '';
        valueEl.textContent = `${icon}${val}`;
      }
    });
  },

  patchLiveSignals(listEl, tickets) {
    const byId = {};
    for (const t of tickets) byId[t.id] = t;
    listEl.querySelectorAll('.ticket-card').forEach((card) => {
      const t = byId[Number(card.dataset.id)];
      if (!t) return;
      const wasLive = card.dataset.live === '1';
      const isLive = t._live;
      if (wasLive !== isLive) {
        card.dataset.live = isLive ? '1' : '0';
        card.classList.toggle('ticket-card--live', isLive);
        const sig = card.querySelector('.ticket-signal--live');
        if (sig) {
          sig.classList.toggle('is-live', isLive);
          sig.classList.toggle('is-offline', !isLive);
          sig.lastChild.textContent = isLive ? 'LIVE' : 'offline';
        }
      }
      card.dataset.stale = t._stale ? '1' : '0';
      const phase = card.querySelector('.ticket-signal--phase');
      if (phase) {
        const p = this.phaseSignal(t);
        phase.textContent = p.text;
        phase.className = `ticket-signal ticket-signal--phase ticket-signal--${p.cls}`;
      }
      const pathEl = card.querySelector('[data-live-path]');
      if (t._live && t._livePath) {
        if (pathEl) pathEl.textContent = t._livePath;
        else {
          const main = card.querySelector('.ticket-card-main');
          if (main) {
            const span = document.createElement('span');
            span.className = 'ticket-card-livepath';
            span.dataset.livePath = '';
            span.textContent = t._livePath;
            main.appendChild(span);
          }
        }
      } else if (pathEl) pathEl.remove();
    });
  },

  renderListHtml(tickets) {
    return tickets.length
      ? `<div class="ticket-card-list">${tickets.map((t) => this.ticketCardHtml(t)).join('')}</div>`
      : '<p class="loading">Nenhum ticket neste filtro</p>';
  },

  async renderListOnly() {
    const listEl = document.getElementById('ticket-list');
    if (!listEl || !state.tickets?.length) return;
    const enriched = state.tickets.map((t) => this.enrichTicket(this.stripEnrichment(t)));
    state.tickets = enriched;
    const filtered = this.applyFilters(enriched);
    const fp = this.listFingerprint(filtered);
    if (fp === this._listFingerprint && listEl.querySelector('.ticket-card')) {
      this.patchLiveSignals(listEl, filtered);
      this.updateKpiStrip(this.computeIndicators(enriched));
      return;
    }
    this._listFingerprint = fp;
    listEl.innerHTML = this.renderListHtml(filtered);
    this.bindList(listEl, filtered);
    this.updateKpiStrip(this.computeIndicators(enriched));
  },

  async softRefresh() {
    if (!this._pageReady || state.view !== 'tickets') return;
    try {
      await this.loadContext();
      const enriched = (state.tickets || []).map((t) => this.enrichTicket(this.stripEnrichment(t)));
      state.tickets = enriched;
      const ind = this.computeIndicators(enriched);
      this.updateKpiStrip(ind);
      const listEl = document.getElementById('ticket-list');
      if (listEl) {
        const filtered = this.applyFilters(enriched);
        const fp = this.listFingerprint(filtered);
        if (fp === this._listFingerprint && listEl.querySelector('.ticket-card')) {
          this.patchLiveSignals(listEl, filtered);
        } else {
          this._listFingerprint = fp;
          const selectedId = state.selectedTicketId;
          listEl.innerHTML = this.renderListHtml(filtered);
          this.bindList(listEl, filtered);
          if (selectedId) {
            listEl.querySelector(`.ticket-card[data-id="${selectedId}"]`)?.classList.add('selected');
          }
        }
      }
      if (state.selectedTicketId && TicketsDetailPanel?.activeTab === 'live') {
        const detailEl = document.getElementById('ticket-detail');
        const sid = detailEl?.dataset?.sessionId || state.selectedSessionId;
        const trail = detailEl?.querySelector('#ticket-detail-live-trail');
        if (sid && trail && window.DeskLive?.renderNavigationTab) {
          await DeskLive.renderNavigationTab(sid, trail);
        }
      }
    } catch { /* ignore poll errors */ }
  },

  async renderPage({ listEl, detailEl, tickets }) {
    this.mountSearchToolbar();
    this.mountQueueBar();
    await this.loadContext();
    const enriched = tickets.map((t) => this.enrichTicket(t));
    state.tickets = enriched;
    const ind = this.computeIndicators(enriched);
    const filtered = this.applyFilters(enriched);
    this._listFingerprint = this.listFingerprint(filtered);

    let strip = document.getElementById('tickets-kpi-strip');
    if (!strip) {
      strip = document.createElement('div');
      strip.id = 'tickets-kpi-strip';
      const view = document.getElementById('view-tickets');
      const searchBar = document.getElementById('tickets-search-bar');
      if (view && searchBar) view.insertBefore(strip, searchBar);
      else if (view) {
        const toolbar = view.querySelector('.toolbar');
        if (toolbar) view.insertBefore(strip, toolbar);
      }
    }
    strip.innerHTML = this.indicatorsHtml(ind);
    this.bindKpiStrip(strip);

    listEl.innerHTML = this.renderListHtml(filtered);
    this.bindList(listEl, filtered);
    this._pageReady = true;

    if (state.selectedTicketId && window.TicketsDetailPanel) {
      await TicketsDetailPanel.render(state.selectedTicketId, detailEl);
    } else if (state.selectedTicketId && typeof renderTicketDetail === 'function') {
      await renderTicketDetail();
    } else if (state.selectedSessionId && typeof renderSessionDetail === 'function') {
      await renderSessionDetail();
    } else if (detailEl) {
      detailEl.innerHTML = '<div class="card detail-panel"><p class="empty">Selecione um ticket para ver detalhes</p></div>';
    }
  },
};

window.TicketsWorkspace = TicketsWorkspace;
