// LogsTab.jsx — Sistem Log İzleme
// SSE ile canlı streaming · Seviye filtresi · Arama & highlight
// Terminal-style viewer (koyu panel) + uygulama temasıyla uyumlu kontrol çubuğu

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

  /* ── Sabitler ─────────────────────────────────────────────────── */
  const LOG_FILES = [
    { key: 'app',         label: 'Uygulama',    hint: 'app.log'                       },
    { key: 'sip',         label: 'SIP / ESL',   hint: 'sip_events.log'                },
    { key: 'audit',       label: 'Denetim',     hint: 'audit.log'                     },
    { key: 'http',        label: 'HTTP',        hint: 'http_access.log'               },
    { key: 'freeswitch',  label: 'FreeSWITCH',  hint: 'freeswitch.log / journalctl'   },
  ];

  const LEVELS = ['ALL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'];

  const LEVEL_STYLE = {
    ERROR:   { fg: '#f87171', bg: 'rgba(248,113,113,.07)', bar: '#f87171' },
    WARNING: { fg: '#fbbf24', bg: 'rgba(251,191,36,.05)',  bar: '#fbbf24' },
    INFO:    { fg: '#cbd5e1', bg: 'transparent',           bar: 'transparent' },
    DEBUG:   { fg: '#475569', bg: 'transparent',           bar: 'transparent' },
    OTHER:   { fg: '#64748b', bg: 'transparent',           bar: 'transparent' },
  };

  const LEVEL_FILTER_COLOR = {
    ALL:     '#5b7a92',
    ERROR:   '#ef4444',
    WARNING: '#f59e0b',
    INFO:    '#3b82f6',
    DEBUG:   '#64748b',
  };

  const MAX_BUF = 2000;  // UI'de tutulacak max satır
  let _uid = 0;

  /* ── Yardımcılar ──────────────────────────────────────────────── */
  function detectLevel(text) {
    // Önce JSON yapısal log kontrolü
    try {
      const o = JSON.parse(text);
      if (o.level) {
        const l = o.level.toUpperCase();
        if (l === 'ERROR' || l === 'CRITICAL') return 'ERROR';
        if (l === 'WARNING' || l === 'WARN') return 'WARNING';
        if (l === 'DEBUG') return 'DEBUG';
        if (l === 'INFO') return 'INFO';
      }
    } catch {}
    if (/\b(ERROR|CRITICAL|CRIT)\b|\[ERR\]/i.test(text))  return 'ERROR';
    if (/\b(WARNING|WARN)\b/i.test(text))                  return 'WARNING';
    if (/\bDEBUG\b/i.test(text))                           return 'DEBUG';
    if (/\bINFO\b/i.test(text))                            return 'INFO';
    return 'OTHER';
  }

  function formatLogLine(raw) {
    try {
      const o = JSON.parse(raw);
      if (!o['@timestamp'] && !o.timestamp && !o.level) return raw;

      // Backend @timestamp UTC olarak yazılır (Elasticsearch/Filebeat standardı).
      // UI'da kullanıcının yerel saatine çevirip göster.
      const rawTs = o['@timestamp'] || o.timestamp || '';
      let ts = '';
      if (rawTs) {
        const d = parseUTC(rawTs);
        ts = d
          ? d.toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit', second: '2-digit' })
          : rawTs.replace(/^.*T/, '').replace(/\.\d{3}Z$/, '');  // fallback (eski davranış)
      }
      const lvl = (o.level || '').toUpperCase().padEnd(7);
      const src = o.logger || o.module || '';
      const msg = o.message || '';

      let line = '';
      if (ts)  line += ts + '  ';
      line += lvl;
      if (src) line += ' [' + src + ']';
      line += '  ' + msg;

      // Exception bilgisi
      if (o.exception && o.exception.type) {
        line += '\n    └─ ' + o.exception.type + ': ' + o.exception.message;
      }

      return line;
    } catch {
      return raw;
    }
  }

  function makeLine(text, hist = false) {
    const level = detectLevel(text);
    const formatted = formatLogLine(text);
    return { id: ++_uid, text: formatted, level, hist };
  }

  function escapeRe(s) {
    return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }

  /* ── Ana Bileşen ──────────────────────────────────────────────── */
  function LogsTab() {
    const [logFile,     setLogFile]     = useState('app');
    const [lines,       setLines]       = useState([]);
    const [filterLevel, setFilterLevel] = useState('ALL');
    const [search,      setSearch]      = useState('');
    const [autoScroll,  setAutoScroll]  = useState(true);
    const [paused,      setPaused]      = useState(false);
    const [status,      setStatus]      = useState('idle'); // idle | connecting | live | error | closed

    const bottomRef   = useRef(null);
    const esRef       = useRef(null);
    const pausedRef   = useRef(false);
    const pendingRef  = useRef([]);      // pause sırasında biriken satırlar
    const autoScrollRef = useRef(true);

    pausedRef.current   = paused;
    autoScrollRef.current = autoScroll;

    /* ── SSE Bağlantısı ─────────────────────────────────────────── */
    const connect = useCallback(() => {
      if (esRef.current) {
        esRef.current.close();
        esRef.current = null;
      }
      pendingRef.current = [];
      setLines([]);
      setStatus('connecting');

      const url = `/api/logs/stream?log_file=${logFile}&lines=150`;
      const es  = new EventSource(url);
      esRef.current = es;

      es.onmessage = (evt) => {
        let msg;
        try { msg = JSON.parse(evt.data); } catch { return; }

        if (msg.t === 'ping') return;

        if (msg.t === 'sep') {
          setStatus('live');
          return;
        }

        if (msg.t === 'error') {
          setLines(prev => [...prev, makeLine(`[HATA] ${msg.text}`, true)]);
          return;
        }

        if (msg.t === 'line' && msg.text) {
          const line = makeLine(msg.text, !!msg.hist);
          if (pausedRef.current) {
            pendingRef.current.push(line);
          } else {
            setLines(prev => {
              const next = [...prev, line];
              return next.length > MAX_BUF ? next.slice(-MAX_BUF) : next;
            });
          }
        }
      };

      es.onerror = () => {
        setStatus('error');
        es.close();
        esRef.current = null;
      };
    }, [logFile]);

    // Dosya değişince yeniden bağlan
    useEffect(() => {
      connect();
      return () => { if (esRef.current) esRef.current.close(); };
    }, [connect]);

    // Tab görünmez olunca bağlantıyı kapat (kaynak tasarrufu)
    useEffect(() => {
      const onVis = () => {
        if (document.hidden) {
          if (esRef.current) { esRef.current.close(); esRef.current = null; setStatus('closed'); }
        } else {
          if (!esRef.current) connect();
        }
      };
      document.addEventListener('visibilitychange', onVis);
      return () => document.removeEventListener('visibilitychange', onVis);
    }, [connect]);

    /* ── Auto-scroll ─────────────────────────────────────────────── */
    useEffect(() => {
      if (autoScrollRef.current && bottomRef.current) {
        bottomRef.current.scrollIntoView({ behavior: 'instant' });
      }
    }, [lines]);

    /* ── Pause / Resume ──────────────────────────────────────────── */
    const togglePause = () => {
      const goLive = paused; // şu an duraklamış → devam
      setPaused(!paused);
      if (goLive && pendingRef.current.length > 0) {
        const pending = pendingRef.current.splice(0);
        setLines(prev => {
          const next = [...prev, ...pending];
          return next.length > MAX_BUF ? next.slice(-MAX_BUF) : next;
        });
      }
    };

    /* ── Filtreli Satırlar (memo) ─────────────────────────────────── */
    const visible = useMemo(() => {
      let out = lines;
      if (filterLevel !== 'ALL') out = out.filter(l => l.level === filterLevel);
      if (search.trim()) {
        const q = search.trim().toLowerCase();
        out = out.filter(l => l.text.toLowerCase().includes(q));
      }
      return out;
    }, [lines, filterLevel, search]);

    /* ── Arama Highlight ─────────────────────────────────────────── */
    function highlight(text) {
      if (!search.trim()) return text;
      const re  = new RegExp(`(${escapeRe(search.trim())})`, 'gi');
      const parts = text.split(re);
      return parts.map((p, i) =>
        re.test(p)
          ? React.createElement('mark', {
              key: i,
              style: { background: '#fef08a', color: '#1a1a1a', borderRadius: 2, padding: '0 1px' },
            }, p)
          : p
      );
    }

    /* ── Durum göstergesi ────────────────────────────────────────── */
    const statusInfo = {
      idle:       { color: '#475569', label: 'Bekleniyor'        },
      connecting: { color: '#f59e0b', label: 'Bağlanıyor...'     },
      live:       { color: '#10b981', label: 'Canlı'             },
      error:      { color: '#ef4444', label: 'Bağlantı kesildi'  },
      closed:     { color: '#64748b', label: 'Duraklatıldı'      },
    }[status] || { color: '#475569', label: status };

    const pendingCount = pendingRef.current.length;

    /* ── Render ──────────────────────────────────────────────────── */
    return (
      <div className="fade-in" style={{
        display: 'flex', flexDirection: 'column',
        height: 'calc(100vh - 70px)', gap: 12,
      }}>

        {/* ═══ Kontrol Çubuğu ═══ */}
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
          background: '#ffffff', borderRadius: 12, padding: '10px 16px',
          boxShadow: '0 2px 8px rgba(0,71,141,.06)',
        }}>

          {/* Durum göstergesi */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, minWidth: 120 }}>
            <span style={{
              width: 8, height: 8, borderRadius: '50%',
              background: statusInfo.color, flexShrink: 0,
              animation: status === 'live' ? 'logLivePulse 2s infinite' : 'none',
            }} />
            <style>{`
              @keyframes logLivePulse {
                0%   { box-shadow: 0 0 0 0 rgba(16,185,129,.5); }
                70%  { box-shadow: 0 0 0 5px rgba(16,185,129,0); }
                100% { box-shadow: 0 0 0 0 rgba(16,185,129,0); }
              }
            `}</style>
            <span style={{ fontSize: 12, fontWeight: 600, color: statusInfo.color }}>
              {statusInfo.label}
            </span>
          </div>

          <div style={{ width: 1, height: 22, background: '#e2e8f0', flexShrink: 0 }} />

          {/* Log Dosyası Seçici */}
          <div style={{ display: 'flex', gap: 4 }}>
            {LOG_FILES.map(f => (
              <button
                key={f.key}
                onClick={() => setLogFile(f.key)}
                title={f.hint}
                style={{
                  padding: '4px 12px', borderRadius: 6, fontSize: 12, fontWeight: 600,
                  cursor: 'pointer', border: 'none', transition: 'all .15s',
                  background: logFile === f.key ? '#00478d' : '#f0f4f8',
                  color:      logFile === f.key ? '#ffffff'  : '#5b7a92',
                }}
              >
                {f.label}
              </button>
            ))}
          </div>

          <div style={{ width: 1, height: 22, background: '#e2e8f0', flexShrink: 0 }} />

          {/* Seviye Filtresi */}
          <div style={{ display: 'flex', gap: 3 }}>
            {LEVELS.map(lvl => {
              const active = filterLevel === lvl;
              const c = LEVEL_FILTER_COLOR[lvl];
              return (
                <button
                  key={lvl}
                  onClick={() => setFilterLevel(lvl)}
                  style={{
                    padding: '3px 9px', borderRadius: 5, fontSize: 11, fontWeight: 600,
                    cursor: 'pointer', transition: 'all .15s',
                    border:      active ? `1px solid ${c}50` : '1px solid transparent',
                    background:  active ? `${c}15`           : 'transparent',
                    color:       active ? c                   : '#8fafc5',
                  }}
                >
                  {lvl}
                </button>
              );
            })}
          </div>

          <div style={{ width: 1, height: 22, background: '#e2e8f0', flexShrink: 0 }} />

          {/* Arama */}
          <div style={{ position: 'relative', flex: 1, minWidth: 160, maxWidth: 320 }}>
            <span style={{ position: 'absolute', left: 8, top: '50%', transform: 'translateY(-50%)', color: '#8fafc5', fontSize: 13, pointerEvents: 'none' }}>
              ⌕
            </span>
            <input
              type="text"
              value={search}
              onChange={e => setSearch(e.target.value)}
              placeholder="Ara... (regex destekli)"
              style={{
                width: '100%', paddingLeft: 26, paddingRight: search ? 26 : 8,
                paddingTop: 5, paddingBottom: 5,
                background: '#f0f4f8', border: '1px solid #dce6ef', borderRadius: 6,
                fontSize: 12, color: '#1a3047', outline: 'none',
                boxSizing: 'border-box',
              }}
            />
            {search && (
              <button
                onClick={() => setSearch('')}
                style={{ position: 'absolute', right: 6, top: '50%', transform: 'translateY(-50%)', background: 'none', border: 'none', cursor: 'pointer', color: '#8fafc5', fontSize: 14, lineHeight: 1, padding: 0 }}
              >×</button>
            )}
          </div>

          {/* Sağ kontroller */}
          <div style={{ marginLeft: 'auto', display: 'flex', gap: 6, alignItems: 'center' }}>
            <span style={{ fontSize: 11, color: '#8fafc5', whiteSpace: 'nowrap' }}>
              {visible.length.toLocaleString('tr-TR')} / {lines.length.toLocaleString('tr-TR')} satır
            </span>

            <button
              onClick={togglePause}
              style={{
                padding: '4px 11px', borderRadius: 6, fontSize: 12, fontWeight: 600,
                cursor: 'pointer', border: 'none',
                background: paused ? '#fef3c7' : '#f0f4f8',
                color:      paused ? '#b45309' : '#5b7a92',
              }}
            >
              {paused
                ? `▶ Devam${pendingCount > 0 ? ` (+${pendingCount})` : ''}`
                : '⏸ Duraklat'}
            </button>

            <button
              onClick={() => { setAutoScroll(a => !a); autoScrollRef.current = !autoScroll; }}
              title="En alta otomatik kaydır"
              style={{
                padding: '4px 11px', borderRadius: 6, fontSize: 12, fontWeight: 600,
                cursor: 'pointer', border: 'none',
                background: autoScroll ? '#eff6ff' : '#f0f4f8',
                color:      autoScroll ? '#1d4ed8'  : '#5b7a92',
              }}
            >
              ↓ Oto
            </button>

            <button
              onClick={() => { setLines([]); pendingRef.current = []; }}
              title="Ekranı temizle"
              style={{
                padding: '4px 11px', borderRadius: 6, fontSize: 12, fontWeight: 600,
                cursor: 'pointer', border: 'none',
                background: '#fef2f2', color: '#dc2626',
              }}
            >
              🗑
            </button>

            <button
              onClick={connect}
              title="Yeniden bağlan"
              style={{
                padding: '4px 11px', borderRadius: 6, fontSize: 12, fontWeight: 600,
                cursor: 'pointer', border: 'none',
                background: '#f0f4f8', color: '#5b7a92',
              }}
            >
              ↻
            </button>
          </div>
        </div>

        {/* ═══ Terminal Görünümü ═══ */}
        <div style={{
          flex: 1, background: '#0d1117',
          borderRadius: 12, overflow: 'auto',
          fontFamily: "'JetBrains Mono','Fira Code','Cascadia Code',Consolas,'Courier New',monospace",
          fontSize: 12, lineHeight: '20px',
          boxShadow: '0 4px 20px rgba(0,0,0,.2)',
          position: 'relative',
        }}>

          {/* Başlık çubuğu */}
          <div style={{
            position: 'sticky', top: 0, zIndex: 10,
            display: 'flex', alignItems: 'center', gap: 8,
            padding: '7px 14px',
            background: '#161b22', borderBottom: '1px solid #21262d',
          }}>
            <span style={{ width: 12, height: 12, borderRadius: '50%', background: '#ff5f57', display: 'inline-block' }} />
            <span style={{ width: 12, height: 12, borderRadius: '50%', background: '#febc2e', display: 'inline-block' }} />
            <span style={{ width: 12, height: 12, borderRadius: '50%', background: '#28c840', display: 'inline-block' }} />
            <span style={{ fontSize: 11, color: '#58a6ff', marginLeft: 6, fontWeight: 600 }}>
              {LOG_FILES.find(f => f.key === logFile)?.hint || 'app.log'}
            </span>
            <span style={{ marginLeft: 'auto', fontSize: 10, color: '#30363d' }}>
              max {MAX_BUF.toLocaleString('tr-TR')} satır buffer
            </span>
          </div>

          {/* Log satırları */}
          {visible.length === 0 ? (
            <div style={{ padding: '40px 20px', textAlign: 'center', color: '#30363d', fontSize: 13 }}>
              {status === 'connecting'
                ? '⟳  Bağlanıyor...'
                : filterLevel !== 'ALL' || search
                  ? 'Filtreyle eşleşen satır yok'
                  : 'Henüz log satırı yok'}
            </div>
          ) : (
            <div style={{ padding: '4px 0' }}>
              {visible.map(line => {
                const ls = LEVEL_STYLE[line.level] || LEVEL_STYLE.OTHER;
                return (
                  <div
                    key={line.id}
                    style={{
                      display: 'flex',
                      alignItems: 'stretch',
                      borderBottom: '1px solid transparent',
                      background: ls.bg,
                      opacity: line.hist ? 0.7 : 1,
                    }}
                  >
                    {/* Sol durum çizgisi */}
                    <span style={{
                      width: 2, flexShrink: 0,
                      background: ls.bar,
                      borderRadius: 1,
                    }} />
                    {/* Satır içeriği */}
                    <span style={{
                      flex: 1,
                      padding: '0 14px',
                      color: ls.fg,
                      whiteSpace: 'pre-wrap',
                      wordBreak: 'break-all',
                    }}>
                      {highlight(line.text)}
                    </span>
                  </div>
                );
              })}
              <div ref={bottomRef} style={{ height: 4 }} />
            </div>
          )}
        </div>

      </div>
    );
  }

  window.LogsTab = LogsTab;
})();
