/* global React */
// EventsPage — page d'observabilité dédiée
// Liste paginée de tous les événements bus (event_logs) + filtres avancés.
// Plus complet que la cloche (qui est limitée à 50 events live).

(function () {
  const { useState, useEffect, useMemo } = React;

  const LEVELS = [
    { key: 'all',   label: 'Tous',     color: 'var(--ink-3)' },
    { key: 'error', label: 'Erreurs',  color: 'var(--rouge)' },
    { key: 'warn',  label: 'Warnings', color: 'var(--amber)' },
    { key: 'info',  label: 'Info',     color: 'var(--signal-deep)' },
    { key: 'debug', label: 'Debug',    color: 'var(--ink-5)' },
  ];

  const NOTIF_ENTITY_NAV_LOCAL = window.NOTIF_ENTITY_NAV || {
    'dossier-cee': 'dossiers', 'opportunity': 'crm', 'lead': 'crm', 'quote': 'crm',
    'contact': 'crm', 'organization': 'crm', 'appointment': 'calendar', 'rdv': 'calendar',
    'signature': 'signatures', 'tech-visit': 'visites', 'visit': 'visites', 'pre-visit': 'visites',
    'etude-reglementaire': 'etudes-reg', 'etude': 'etudes-reg', 'solar': 'solar',
    'solar-project': 'solar', 'email': 'comm', 'devis': 'devis', 'product': 'products',
    'webhook': 'webhooks', 'collaborator': 'equipe',
  };

  function fmtTime(ts) {
    if (!ts) return '';
    const d = new Date(ts);
    return d.toLocaleString('fr-FR', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit', second: '2-digit' });
  }

  function EventsPage() {
    const BASE = (window.AE_API && window.AE_API.BASE) || '';
    const [events, setEvents] = useState([]);
    const [loading, setLoading] = useState(false);
    const [filterLevel, setFilterLevel]   = useState('all');
    const [filterSource, setFilterSource] = useState('all');
    const [filterType, setFilterType]     = useState('all');
    const [search, setSearch]             = useState('');
    const [showNoisy, setShowNoisy]       = useState(false);
    const [limit, setLimit]               = useState(200);

    const fetchEvents = async () => {
      setLoading(true);
      try {
        const r = await fetch(`${BASE}/api/events?limit=${limit}`).then(x => x.json());
        if (r.ok) setEvents(r.events || []);
      } catch (_) {}
      setLoading(false);
    };

    useEffect(() => { fetchEvents(); }, [limit]);

    // Live SSE — on prepend les nouveaux events
    useEffect(() => {
      const es = new EventSource(`${BASE}/api/events/stream`);
      es.onmessage = (e) => {
        try {
          const evt = JSON.parse(e.data);
          setEvents(prev => [evt, ...prev].slice(0, 500));
        } catch (_) {}
      };
      return () => es.close();
    }, [BASE]);

    // Sources et types disponibles (pour les selects)
    const sources = useMemo(() => {
      const s = new Set();
      events.forEach(e => e.source && s.add(e.source));
      return ['all', ...Array.from(s).sort()];
    }, [events]);

    const types = useMemo(() => {
      const t = new Set();
      events.forEach(e => e.type && t.add(e.type));
      return ['all', ...Array.from(t).sort()];
    }, [events]);

    // Filtrage
    const filtered = events.filter(e => {
      if (!showNoisy) {
        const noisy = ['api.get.', 'api.post.', 'api.patch.', 'api.put.', 'api.delete.'];
        if (noisy.some(p => (e.type || '').startsWith(p))) return false;
      }
      if (filterLevel !== 'all' && e.level !== filterLevel) return false;
      if (filterSource !== 'all' && e.source !== filterSource) return false;
      if (filterType !== 'all' && e.type !== filterType) return false;
      if (search) {
        const q = search.toLowerCase();
        const hay = `${e.title || ''} ${e.message || ''} ${e.type || ''} ${e.source || ''}`.toLowerCase();
        if (!hay.includes(q)) return false;
      }
      return true;
    });

    // Stats par niveau (sur l'ensemble non filtré)
    const stats = useMemo(() => {
      const c = { error: 0, warn: 0, info: 0, debug: 0 };
      events.forEach(e => { if (c[e.level] !== undefined) c[e.level]++; });
      return c;
    }, [events]);

    const handleNav = (e) => {
      const kind = e.entity?.kind;
      const target = NOTIF_ENTITY_NAV_LOCAL[kind];
      if (target && window.AE_NAV) {
        try { window.AE_NOTIF_TARGET = { kind, id: e.entity?.id, ref: e.entity?.ref, type: e.type }; } catch (_) {}
        window.AE_NAV(target);
      }
    };

    const exportJson = () => {
      const blob = new Blob([JSON.stringify(filtered, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `events-${new Date().toISOString().slice(0, 16).replace(':', '-')}.json`;
      a.click();
      URL.revokeObjectURL(url);
    };

    return (
      <div style={{ padding: '20px 24px', maxWidth: 1200, margin: '0 auto' }}>
        {/* Header */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
          <h1 style={{ fontSize: 20, fontWeight: 700, letterSpacing: '-0.02em', margin: 0 }}>Événements</h1>
          <span style={{ fontSize: 11, color: 'var(--ink-4)' }}>· flux observabilité temps réel</span>
          <span style={{ flex: 1 }} />
          <button onClick={fetchEvents} disabled={loading}
            style={{ padding: '6px 12px', fontSize: 12, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
            {loading ? 'Chargement…' : '⟳ Rafraîchir'}
          </button>
          <button onClick={exportJson}
            style={{ padding: '6px 12px', fontSize: 12, border: '1px solid var(--line)', borderRadius: 6, background: 'var(--paper-2)' }}>
            ⬇ Export JSON
          </button>
        </div>

        {/* Stats */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, marginBottom: 16 }}>
          {[
            ['error', 'Erreurs', 'var(--rouge)'],
            ['warn',  'Warnings', 'var(--amber)'],
            ['info',  'Info', 'var(--signal-deep)'],
            ['debug', 'Debug', 'var(--ink-5)'],
          ].map(([k, label, color]) => (
            <div key={k} style={{ padding: '12px 14px', border: '1px solid var(--line)', borderRadius: 8, background: 'var(--paper-2)' }}>
              <div style={{ fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, marginBottom: 4 }}>{label}</div>
              <div style={{ fontSize: 22, fontWeight: 700, color }}>{stats[k] || 0}</div>
            </div>
          ))}
        </div>

        {/* Filtres */}
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center', marginBottom: 12, padding: 12, background: 'var(--paper-2)', border: '1px solid var(--line)', borderRadius: 8 }}>
          <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Rechercher dans titre/message…"
            style={{ flex: 1, minWidth: 200, padding: '6px 10px', border: '1px solid var(--line)', borderRadius: 5, fontSize: 12, background: 'var(--paper)', color: 'var(--ink)' }} />
          <select value={filterLevel} onChange={e => setFilterLevel(e.target.value)}
            style={{ padding: '6px 10px', border: '1px solid var(--line)', borderRadius: 5, fontSize: 12, background: 'var(--paper)', color: 'var(--ink)' }}>
            {LEVELS.map(l => <option key={l.key} value={l.key}>{l.label}</option>)}
          </select>
          <select value={filterSource} onChange={e => setFilterSource(e.target.value)}
            style={{ padding: '6px 10px', border: '1px solid var(--line)', borderRadius: 5, fontSize: 12, background: 'var(--paper)', color: 'var(--ink)', minWidth: 120 }}>
            {sources.map(s => <option key={s} value={s}>{s === 'all' ? 'Toutes sources' : s}</option>)}
          </select>
          <select value={filterType} onChange={e => setFilterType(e.target.value)}
            style={{ padding: '6px 10px', border: '1px solid var(--line)', borderRadius: 5, fontSize: 12, background: 'var(--paper)', color: 'var(--ink)', minWidth: 160 }}>
            {types.slice(0, 60).map(t => <option key={t} value={t}>{t === 'all' ? 'Tous les types' : t}</option>)}
          </select>
          <select value={limit} onChange={e => setLimit(Number(e.target.value))}
            style={{ padding: '6px 10px', border: '1px solid var(--line)', borderRadius: 5, fontSize: 12, background: 'var(--paper)', color: 'var(--ink)' }}>
            <option value={100}>100</option>
            <option value={200}>200</option>
            <option value={500}>500</option>
          </select>
          <label style={{ fontSize: 11, color: 'var(--ink-3)', display: 'flex', alignItems: 'center', gap: 5 }}>
            <input type="checkbox" checked={showNoisy} onChange={e => setShowNoisy(e.target.checked)} />
            Afficher api.* (bruit middleware)
          </label>
        </div>

        {/* Tableau */}
        <div style={{ border: '1px solid var(--line)', borderRadius: 8, overflow: 'hidden' }}>
          <div style={{ display: 'grid', gridTemplateColumns: '120px 60px 100px 1fr 100px', padding: '8px 12px', background: 'var(--paper-3)', borderBottom: '1px solid var(--line)', fontSize: 10, color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: 0.6, fontWeight: 600 }}>
            <span>Quand</span>
            <span>Niveau</span>
            <span>Source</span>
            <span>Titre / message</span>
            <span style={{ textAlign: 'right' }}>Entité</span>
          </div>
          <div style={{ maxHeight: 'calc(100vh - 380px)', overflowY: 'auto' }}>
            {filtered.length === 0 ? (
              <div style={{ padding: '40px 20px', textAlign: 'center', color: 'var(--ink-4)', fontSize: 13 }}>
                Aucun événement ne correspond aux filtres
              </div>
            ) : filtered.map((e, i) => {
              const navKind = e.entity?.kind || e.entityKind;
              const canNav = navKind && NOTIF_ENTITY_NAV_LOCAL[navKind];
              const lvlColor = LEVELS.find(l => l.key === e.level)?.color || 'var(--ink-4)';
              return (
                <div key={e.id || e.eventId || i}
                  onClick={() => canNav && handleNav(e)}
                  style={{
                    display: 'grid', gridTemplateColumns: '120px 60px 100px 1fr 100px',
                    padding: '8px 12px', borderBottom: '1px solid var(--hairline)',
                    fontSize: 12, alignItems: 'start',
                    cursor: canNav ? 'pointer' : 'default',
                    transition: 'background 100ms',
                  }}
                  onMouseEnter={ev => { if (canNav) ev.currentTarget.style.background = 'var(--paper-2)'; }}
                  onMouseLeave={ev => { ev.currentTarget.style.background = 'transparent'; }}>
                  <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)' }}>{fmtTime(e.ts)}</span>
                  <span className="mono" style={{ fontSize: 9, padding: '2px 6px', borderRadius: 4, color: lvlColor, border: `1px solid ${lvlColor}`, fontWeight: 600, alignSelf: 'flex-start', justifySelf: 'flex-start' }}>{e.level || 'info'}</span>
                  <span className="mono" style={{ fontSize: 10, color: 'var(--ink-3)' }}>{e.source || '—'}</span>
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontWeight: 500, color: 'var(--ink)', lineHeight: 1.3 }}>
                      {e.title || e.type}
                      {canNav && <span style={{ color: 'var(--ink-5)', marginLeft: 6, fontSize: 10 }}>→</span>}
                    </div>
                    {e.message && <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2, lineHeight: 1.4 }}>{e.message.slice(0, 200)}{e.message.length > 200 ? '…' : ''}</div>}
                    <div className="mono" style={{ fontSize: 9, color: 'var(--ink-5)', marginTop: 3 }}>{e.type}</div>
                  </div>
                  <span className="mono" style={{ fontSize: 10, color: 'var(--ink-4)', textAlign: 'right' }}>
                    {navKind ? `${navKind}#${e.entity?.id || e.entityId || '—'}` : '—'}
                  </span>
                </div>
              );
            })}
          </div>
          <div style={{ padding: '8px 12px', borderTop: '1px solid var(--line)', background: 'var(--paper-3)', fontSize: 11, color: 'var(--ink-4)', textAlign: 'right' }}>
            {filtered.length} événement{filtered.length > 1 ? 's' : ''} affiché{filtered.length > 1 ? 's' : ''} · {events.length} total
          </div>
        </div>
      </div>
    );
  }

  Object.assign(window, { EventsPage });
})();
