import React, { useEffect, useMemo, useRef, useState } from 'react';
import { formatTime } from '../utils/format.js';

const MAX_ENTRIES = 800;
const MAX_TRAFFIC = 500;
const GROUP_WINDOW_MS = 30_000;

function normalizeLine(line) {
  return String(line || '').replace(/\x1b\[\d+m/g, '').trim();
}

function groupEntries(entries) {
  const out = [];
  for (const e of entries) {
    const key = `${e.level}|${normalizeLine(e.line)}`;
    const last = out[out.length - 1];
    const ts = new Date(e.ts).getTime();
    if (last && last._key === key && ts - last._lastTs < GROUP_WINDOW_MS) {
      last.count += 1;
      last._lastTs = ts;
      last.lastTs = e.ts;
    } else {
      out.push({ ...e, _key: key, _lastTs: ts, count: 1, lastTs: e.ts });
    }
  }
  return out;
}

const CATEGORY_BADGE = {
  direct: { cls: 'success', label: 'direct' },
  vpn:    { cls: 'info',    label: 'VPN' },
  block:  { cls: 'danger',  label: 'block' },
  other:  { cls: '',        label: 'other' },
};

function getDeviceName(sourceIp, devices) {
  if (!sourceIp || !devices?.length) return null;
  for (const d of devices) {
    if (d.enabled === false) continue;
    const ip = d.ip || d.sourceIp || (d.sourceIps || [])[0];
    const plain = ip?.endsWith('/32') ? ip.slice(0, -3) : ip;
    if (plain === sourceIp) return d.name;
  }
  return null;
}

function groupTraffic(list, sortBy = 'time') {
  const map = new Map();
  for (const e of list) {
    const key = `${e.sourceIp || ''}|${e.category}|${e.host}|${e.port}|${e.matchedRule || ''}`;
    const ts = new Date(e.ts).getTime();
    if (map.has(key)) {
      const g = map.get(key);
      g.count++;
      g._lastTs = ts;
      g.lastTs = e.ts;
    } else {
      map.set(key, { ...e, _key: key, _lastTs: ts, count: 1, lastTs: e.ts });
    }
  }
  const arr = Array.from(map.values());
  if (sortBy === 'count') return arr.sort((a, b) => b.count - a.count || b._lastTs - a._lastTs);
  return arr.sort((a, b) => b._lastTs - a._lastTs);
}

function TrafficTab({ devices = [] }) {
  const [traffic, setTraffic] = useState([]);
  const [paused, setPaused] = useState(false);
  const [filter, setFilter] = useState('all'); // all | direct | vpn | block
  const [search, setSearch] = useState('');
  const [grouped, setGrouped] = useState(true);
  const [sortBy, setSortBy] = useState('count'); // time | count
  const [autoscroll, setAutoscroll] = useState(true);
  const containerRef = useRef(null);
  const pausedRef = useRef(false);

  useEffect(() => { pausedRef.current = paused; }, [paused]);

  useEffect(() => {
    const source = new EventSource('/api/traffic/stream');
    source.onmessage = (ev) => {
      if (pausedRef.current) return;
      try {
        const entry = JSON.parse(ev.data);
        setTraffic((prev) => {
          const next = [...prev, entry];
          if (next.length > MAX_TRAFFIC) next.splice(0, next.length - MAX_TRAFFIC);
          return next;
        });
      } catch {}
    };
    return () => source.close();
  }, []);

  const filtered = useMemo(() => {
    let list = traffic;
    if (filter !== 'all') list = list.filter((e) => e.category === filter);
    if (search) {
      const s = search.toLowerCase();
      list = list.filter((e) =>
        e.host?.toLowerCase().includes(s) ||
        String(e.port || '').includes(s) ||
        e.outbound?.toLowerCase().includes(s) ||
        e.matchedRule?.toLowerCase().includes(s) ||
        e.sourceIp?.toLowerCase().includes(s) ||
        getDeviceName(e.sourceIp, devices)?.toLowerCase().includes(s),
      );
    }
    return grouped ? groupTraffic(list, sortBy) : list;
  }, [traffic, filter, search, grouped, sortBy, devices]);

  useEffect(() => {
    if (!autoscroll || !containerRef.current) return;
    containerRef.current.scrollTop = containerRef.current.scrollHeight;
  }, [filtered, autoscroll]);

  const counts = useMemo(() => {
    const c = { direct: 0, vpn: 0, block: 0 };
    for (const e of traffic) if (e.category in c) c[e.category]++;
    return c;
  }, [traffic]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', flex: 1, overflow: 'hidden' }}>
      <div className="filter-bar" style={{ marginBottom: 12, flexWrap: 'wrap', gap: 8 }}>
        <input
          className="input"
          placeholder="Поиск: host, порт, правило…"
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          style={{ flex: 1, minWidth: 180 }}
        />
        <select className="select" value={filter} onChange={(e) => setFilter(e.target.value)}>
          <option value="all">Все ({traffic.length})</option>
          <option value="direct">direct ({counts.direct})</option>
          <option value="vpn">VPN ({counts.vpn})</option>
          <option value="block">block ({counts.block})</option>
        </select>
        <label className="checkbox">
          <input type="checkbox" checked={grouped} onChange={(e) => setGrouped(e.target.checked)} />
          Группировать
        </label>
        {grouped && (
          <select className="select" value={sortBy} onChange={(e) => setSortBy(e.target.value)} style={{ width: 'auto' }}>
            <option value="count">По частоте</option>
            <option value="time">По времени</option>
          </select>
        )}
        <label className="checkbox">
          <input type="checkbox" checked={autoscroll} onChange={(e) => setAutoscroll(e.target.checked)} />
          Автоскролл
        </label>
        <button className="btn btn-ghost sm" onClick={() => setPaused((p) => !p)}>
          {paused ? '▶ Продолжить' : '⏸ Пауза'}
        </button>
        <button
          className="btn btn-ghost sm"
          onClick={() => { setTraffic([]); fetch('/api/traffic', { method: 'DELETE' }).catch(() => {}); }}
        >
          Очистить
        </button>
      </div>

      {traffic.length === 0 ? (
        <div className="muted" style={{ padding: '20px 0', textAlign: 'center' }}>
          Ожидаем трафик… Убедитесь что sing-box запущен и уровень логов не выше INFO.
        </div>
      ) : (
        <div ref={containerRef} style={{ flex: 1, overflow: 'auto' }}>
          <table className="table" style={{ fontSize: 12 }}>
            <thead>
              <tr>
                <th style={{ width: 70 }}>Время</th>
                <th style={{ width: 70 }}>Туннель</th>
                <th style={{ width: 110 }}>Устройство</th>
                <th>Хост / IP</th>
                <th style={{ width: 55 }}>Порт</th>
                <th>Правило</th>
                <th style={{ width: 40 }}></th>
              </tr>
            </thead>
            <tbody>
              {filtered.map((e, i) => {
                const badge = CATEGORY_BADGE[e.category] || CATEGORY_BADGE.other;
                const deviceName = getDeviceName(e.sourceIp, devices);
                return (
                  <tr key={i} style={{ opacity: e.category === 'block' ? 0.6 : 1 }}>
                    <td className="muted text-mono" style={{ whiteSpace: 'nowrap' }}>{formatTime(e.ts)}</td>
                    <td>
                      <span className={`badge ${badge.cls}`} style={{ fontSize: 11 }}>{badge.label}</span>
                    </td>
                    <td className="text-mono" style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 110 }}>
                      {deviceName
                        ? <span style={{ fontSize: 11 }}>{deviceName}</span>
                        : e.sourceIp
                          ? <span className="muted" style={{ fontSize: 10 }}>{e.sourceIp}</span>
                          : <span className="muted" style={{ fontSize: 11 }}>—</span>}
                    </td>
                    <td className="text-mono" style={{ wordBreak: 'break-all' }}>{e.host || '—'}</td>
                    <td className="muted text-mono">{e.port || '—'}</td>
                    <td>
                      {e.matchedRule
                        ? <span className="badge info" style={{ fontSize: 11 }}>{e.matchedRule}</span>
                        : <span className="muted" style={{ fontSize: 11 }}>—</span>}
                    </td>
                    <td className="muted text-mono" style={{ textAlign: 'right', fontSize: 11 }}>
                      {e.count > 1 && <span className="repeat">×{e.count}</span>}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

export function LogsPage({ devices = [] }) {
  const [tab, setTab] = useState('traffic'); // traffic | logs
  const [entries, setEntries] = useState([]);
  const [paused, setPaused] = useState(false);
  const [filter, setFilter] = useState('all');
  const [search, setSearch] = useState('');
  const [autoscroll, setAutoscroll] = useState(true);
  const [grouped, setGrouped] = useState(true);
  const containerRef = useRef(null);
  const pausedRef = useRef(false);

  useEffect(() => { pausedRef.current = paused; }, [paused]);

  useEffect(() => {
    const source = new EventSource('/api/logs/stream');
    source.onmessage = (event) => {
      if (pausedRef.current) return;
      try {
        const entry = JSON.parse(event.data);
        setEntries((prev) => {
          const next = [...prev, entry];
          if (next.length > MAX_ENTRIES) next.splice(0, next.length - MAX_ENTRIES);
          return next;
        });
      } catch {}
    };
    return () => source.close();
  }, []);

  const filtered = useMemo(() => {
    let list = entries;
    if (filter !== 'all') list = list.filter((e) => e.level === filter);
    if (search) {
      const s = search.toLowerCase();
      list = list.filter((e) => normalizeLine(e.line).toLowerCase().includes(s));
    }
    return grouped ? groupEntries(list) : list;
  }, [entries, filter, search, grouped]);

  useEffect(() => {
    if (!autoscroll || !containerRef.current) return;
    containerRef.current.scrollTop = containerRef.current.scrollHeight;
  }, [filtered, autoscroll]);

  function copy(text) {
    navigator.clipboard?.writeText(text).catch(() => {});
  }

  return (
    <div className="card" style={{ display: 'flex', flexDirection: 'column', minHeight: 'calc(100vh - 160px)' }}>
      <div className="card-header">
        <h2>Логи sing-box</h2>
        <div className="tabs" style={{ marginLeft: 'auto', marginBottom: 0 }}>
          <button className={`tab ${tab === 'traffic' ? 'active' : ''}`} onClick={() => setTab('traffic')}>Трафик</button>
          <button className={`tab ${tab === 'logs' ? 'active' : ''}`} onClick={() => setTab('logs')}>Системные логи</button>
        </div>
      </div>

      {tab === 'traffic' && <TrafficTab devices={devices} />}

      {tab === 'logs' && (
        <>
          <div className="filter-bar" style={{ marginBottom: 12 }}>
            <input
              className="input"
              placeholder="Поиск по тексту…"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              style={{ flex: 1, minWidth: 200 }}
            />
            <select className="select" value={filter} onChange={(e) => setFilter(e.target.value)}>
              <option value="all">Все уровни</option>
              <option value="info">info</option>
              <option value="warning">warning</option>
              <option value="error">error</option>
              <option value="debug">debug</option>
            </select>
            <label className="checkbox"><input type="checkbox" checked={grouped} onChange={(e) => setGrouped(e.target.checked)} /> Группировать</label>
            <label className="checkbox"><input type="checkbox" checked={autoscroll} onChange={(e) => setAutoscroll(e.target.checked)} /> Автоскролл</label>
            <button className="btn btn-ghost sm" onClick={() => setPaused((p) => !p)}>{paused ? '▶ Продолжить' : '⏸ Пауза'}</button>
            <button className="btn btn-ghost sm" onClick={() => setEntries([])}>Очистить</button>
          </div>

          <div ref={containerRef} className="logs-stream">
            {filtered.length === 0 && <p className="muted">Логов пока нет.</p>}
            {filtered.map((entry, index) => {
              const text = normalizeLine(entry.line);
              if (grouped && entry.count > 1) {
                return (
                  <div key={`${entry.ts}-${index}`} className="log-group">
                    <span className="log-time mono">{formatTime(entry.ts)}</span>
                    <span className={`log-level text-${entry.level === 'error' ? 'danger' : entry.level === 'warning' ? 'warning' : 'info'}`}>
                      {entry.level}
                    </span>
                    <span className="log-text">{text}</span>
                    <span className="repeat">×{entry.count}</span>
                  </div>
                );
              }
              return (
                <div
                  key={`${entry.ts}-${index}`}
                  className={`log-line ${entry.level}`}
                  onDoubleClick={() => copy(`${formatTime(entry.ts)} ${entry.level} ${text}`)}
                  title="Двойной клик — скопировать"
                >
                  <span className="log-time">{formatTime(entry.ts)}</span>
                  <span className="log-level">{entry.level}</span>
                  <span className="log-text">{text}</span>
                </div>
              );
            })}
          </div>
        </>
      )}
    </div>
  );
}
