// main.js (ES6+ Refactor)
import { backendUrl } from './config.js'
let lastEvents = [];
let sortField = null;
let sortAsc = true;
let chart;
let lastSummary = null;
let hasRecentEvents = false;

const byId = (id) => document.getElementById(id);
const translations = {
  ru: {
    title: "AI Анализатор",
    main_title: "AI Анализатор Событий Suricata",
    manual_input_label: "Вставьте JSON-массив событий (ручной режим):",
    analyze: "Анализировать",
    anomaly_only: "Только аномалии",
    redis_analysis: "Анализ Flow-событий из Redis",
    redis_analysisTLS: "Анализ TLS-событий из Redis",
    redis_analysisDNS: "Анализ DNS-событий из Redis",
    redis_analysisHTTP: "Анализ HTTP-событий из Redis",
    analysis_params: "Параметры анализа:",
    auto_refresh: "Автообновление (каждые 2 мин.)",
    limit_label: "Лимит:",
    offset_label: "Смещение:",
    download_csv: "Скачать CSV",
    download_json: "Скачать JSON",
    source: "Источник",
    destination: "Назначение",
    anomaly: "Аномалия",
    details: "Детали",
    block: "Блокировка",
    timeline_chart: "График аномалий по времени",
    interval: "Интервал:",
    per_minute: "по минутам",
    per_hour: "по часам",
    per_day: "по дням",
    show_chart: "Показать график",
    compare_today_vs_yesterday: "Сравнение аномалий: сегодня vs вчера",
    hour_interval: "Часовой интервал:",
    compare: "Сравнить",
    hourly_compare: "Почасовое сравнение: Сегодня vs Вчера",
    show: "Показать",
    limit_too_high: "Вы выбрали слишком большой объем для анализа. Рекомендуется до 100000 событий.",
    error_invalid_json: "Некорректный JSON",
    error_array_expected: "Ожидается массив объектов",
    error_request: "Ошибка запроса",
    error_api: "Ошибка",
    total_events: "Всего событий",
    anomalies_found: "Аномалий",
    tab_flow: "Анализатор Flow Events",
    tab_tls: "Анализатор TLS events",
    tab_dns: "Анализ DNS events",
    tab_http: "Анализ HTTP events",
    tab_complex: "Комплексный анализ",
    tab_multianalysis: "Комплексный анализ мультианомалий"
  },
  en: {
    title: "AI Analyzer",
    main_title: "AI Suricata Event Analyzer",
    manual_input_label: "Paste JSON array of events (manual mode):",
    analyze: "Analyze",
    anomaly_only: "Anomalies only",
    redis_analysis: "Flow Event Analysis from Redis",
    redis_analysisTLS: "TLS Event Analysis from Redis",
    redis_analysisDNS: "DNS Event Analysis from Redis",
    redis_analysisHTTP: "HTTP Event Analysis from Redis",
    analysis_params: "Analysis Parameters:",
    auto_refresh: "Auto-refresh (every 2 min.)",
    limit_label: "Limit:",
    offset_label: "Offset:",
    download_csv: "Download CSV",
    download_json: "Download JSON",
    source: "Source",
    destination: "Destination",
    anomaly: "Anomaly",
    details: "Details",
    block: "Block",
    timeline_chart: "Anomaly Timeline Chart",
    interval: "Interval:",
    per_minute: "per minute",
    per_hour: "per hour",
    per_day: "per day",
    show_chart: "Show Chart",
    compare_today_vs_yesterday: "Anomaly Comparison: Today vs Yesterday",
    hour_interval: "Hour Interval:",
    compare: "Compare",
    hourly_compare: "Hourly Comparison: Today vs Yesterday",
    show: "Show",
    limit_too_high: "You selected too many events. Recommended maximum is 100,000.",
    error_invalid_json: "Invalid JSON",
    error_array_expected: "Expected an array of objects",
    error_request: "Request failed",
    error_api: "Error",
    total_events: "Total events",
    anomalies_found: "Anomalies found",
    tab_flow: "Flow Events Analyzer",
    tab_tls: "TLS Events Analyzer",
    tab_dns: "DNS Events Analyzer",
    tab_http: "HTTP Events Analyzer",
    tab_complex: "Complex Analysis",
    tab_multianalysis: "Multianomaly Analysis"
  }
};
const t = (key) => {
  const lang = localStorage.getItem('lang') || 'ru';
  return translations[lang]?.[key] || key;
};

const applyLanguage = (lang) => {
  const dict = translations[lang] || translations['ru'];
  document.querySelectorAll('[data-i18n]').forEach(el => {
    const key = el.getAttribute('data-i18n');
    if (dict[key]) el.textContent = dict[key];
  });
  localStorage.setItem('lang', lang);
  if (lastSummary) {
    showSummary(lastSummary.total, lastSummary.anomalies, lastSummary.visible);
  }
};

const initLanguage = () => {
  const lang = localStorage.getItem('lang') || 'ru';
  const select = byId('langSelect');
  if (select) select.value = lang;
  applyLanguage(lang);
  if (select) {
    select.addEventListener('change', (e) => {
      applyLanguage(e.target.value);
    });
  }
};


const saveState = () => {
    localStorage.setItem('limit', byId('limitInput').value);
    localStorage.setItem('offset', byId('offsetInput').value);
    localStorage.setItem('anomalyOnly', byId('anomalyOnlyCheckbox').checked);
    localStorage.setItem('interval', byId('intervalSelect').value);
  };
  
  const loadState = () => {
    if (localStorage.getItem('limit')) byId('limitInput').value = localStorage.getItem('limit');
    if (localStorage.getItem('offset')) byId('offsetInput').value = localStorage.getItem('offset');
    if (localStorage.getItem('anomalyOnly')) byId('anomalyOnlyCheckbox').checked = localStorage.getItem('anomalyOnly') === 'true';
    if (localStorage.getItem('interval')) byId('intervalSelect').value = localStorage.getItem('interval');
  };
  const analyzeFlow = async () => {
    const input = byId('jsonInput').value;
    const errorBox = byId('error');
    const resultBox = byId('result');
    errorBox.textContent = '';
    resultBox.innerHTML = '';
  
    let events;
    try {
      events = JSON.parse(input);
      if (!Array.isArray(events)) throw new Error(t('error_array_expected'));
    } catch (err) {
      errorBox.textContent = t('error_invalid_json') + ': ' + err.message;
      return;
    }
  
    try {
      const res = await fetch(`${backendUrl}/ai/analyze/flow`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ events })
      });
      const data = await res.json();
  
      if (data.error) {
        errorBox.textContent = t('error_api') + ': ' + data.error;
      } else {
        resultBox.innerHTML = `
          <p><strong>${t('total_events')}:</strong> ${data.total}</p>
          <p><strong>${t('anomalies_found')}:</strong> ${data.anomaly_count}</p>
          <pre>${JSON.stringify(data.anomalies, null, 2)}</pre>
        `;
      }
    } catch (err) {
      errorBox.textContent = t('error_request') + ': ' + err.message;
    }
  };
  

const fetchAndAnalyzeFlows = async () => {
  const limit = parseInt(byId('limitInput').value) || 100;
  if (limit > 100000) {
    alert(t('limit_too_high'));
    return;
  }
  const offset = parseInt(byId('offsetInput').value) || 0;
  const onlyAnomalies = byId('anomalyOnlyCheckbox').checked;
  

  try {
    const url = `${backendUrl}/api/analyze/flow?offset=${offset}&limit=${limit}&only_anomalies=${onlyAnomalies}`;
    const res = await fetch(url);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);

    const data = await res.json();
    if (data.error) throw new Error(data.error);

    lastEvents = data.events;
    hasRecentEvents = data.events.length > 0;
    sortField = null;
    sortAsc = true;

    byId('flow-results').innerHTML = '';
    byId('detailsBox').innerHTML = '';

    const visibleCount = onlyAnomalies ? limit : data.events.length;
    showSummary(data.total, data.anomaly_count, visibleCount);
    renderFlowEvents(data.events);
  } catch (err) {
    byId('flow-results').innerHTML = `<tr><td colspan="7" class="error">Error: ${err.message}</td></tr>`;
  }
};

const showSummary = (total, anomalies, visible) => {
  const lang = localStorage.getItem('lang') || 'ru';
  const percent = ((anomalies / (visible || 1)) * 100).toFixed(2);
  lastSummary = { total, anomalies, visible };
  const summaryText = {
    ru: `
      <p><strong>Total in Redis:</strong> ${total} events</p>
      <p><strong>In sample:</strong> ${visible}, anomalies found: ${anomalies} (${percent}%)</p>
    `,
    en: `
      <p><strong>Total in Redis:</strong> ${total} events</p>
      <p><strong>In selection:</strong> ${visible}, anomalies found: ${anomalies} (${percent}%)</p>
    `
  };

  byId('summaryBox').innerHTML = summaryText[lang];
};


const renderFlowEvents = (events) => {
  const tbody = byId('flow-results');
  tbody.innerHTML = '';
  events.forEach(({ index, src_ip, dst_ip, anomaly, full }) => {
    const {
      src_port,
      dest_port,
      proto,
      app_proto
    } = full;

    const row = document.createElement('tr');
    row.className = anomaly ? 'anomaly' : 'normal';
    row.innerHTML = `
      <td>${index + 1}</td>
      <td>${src_ip}:${src_port || ''}</td>
      <td>${dst_ip}:${dest_port || ''}</td>
      <td>${proto || ''}</td>
      <td>${app_proto || ''}</td>
      <td>${anomaly ? 'Yes 🚨' : 'No ✅'}</td>
      <td><button style="font-size: 12px; padding: 2px 6px;" onclick='showDetails(${JSON.stringify(full)})'>🔍</button></td>
      <td><button style="font-size: 12px; padding: 2px 6px;" onclick='copySuricataRule("${src_ip}")'>⚡</button></td>
    `;
    tbody.appendChild(row);
  });
};


const sortTableBy = (field) => {
  if (sortField === field) {
    sortAsc = !sortAsc;
  } else {
    sortField = field;
    sortAsc = true;
  }

  const getValue = (obj) => {
    return (
      obj[field] ??
      obj.http?.[field] ??
      obj.full?.[field] ??
      obj.full?.http?.[field] ??
      ''
    );
  };

  const isNumeric = (val) =>
    typeof val === 'number' || (!isNaN(val) && val !== '');

  lastEvents.sort((a, b) => {
    const valA = getValue(a);
    const valB = getValue(b);

    // Explicit check for boolean field "anomaly"
    if (field === 'anomaly') {
      return sortAsc
        ? (valA === valB ? 0 : valA ? -1 : 1)
        : (valA === valB ? 0 : valA ? 1 : -1);
    }

    // If both values ​​are numeric, sort as numbers
    if (isNumeric(valA) && isNumeric(valB)) {
      return sortAsc ? valA - valB : valB - valA;
    }

    // Otherwise, we sort as strings
    const strA = String(valA).toLowerCase();
    const strB = String(valB).toLowerCase();

    if (strA < strB) return sortAsc ? -1 : 1;
    if (strA > strB) return sortAsc ? 1 : -1;
    return 0;
  });

  renderFlowEvents(lastEvents);
};



window.sortTableBy = sortTableBy;
window.showDetails = (event) => {
  byId('detailsBox').innerHTML = `<h3>Event details:</h3><pre>${JSON.stringify(event, null, 2)}</pre>`;
  byId('detailsBox').scrollIntoView({ behavior: 'smooth' });
};

// JS function for generating a rule and showing a modal window
window.copySuricataRule = (ip) => {
  const rule = `drop ip [${ip}] any -> any any (msg:"Blocked malicious IP ${ip}"; sid:999001; rev:1;)`;
  
  // Insert a rule into a modal window
  const modal = document.getElementById('suricataModal');
  const ruleBox = document.getElementById('suricataRule');
  
  if (modal && ruleBox) {
    ruleBox.textContent = rule;
    modal.style.display = 'block';
  } else {
    alert('Error: Failed to display rule.');
  }
};


// Charts
const loadTimelineChart = async () => {
  const interval = byId('intervalSelect').value;
  const limit = parseInt(byId('limitInput').value) || 100;
  const offset = parseInt(byId('offsetInput').value) || 0;
  const url = `${backendUrl}/api/analyze_flow_timeline?interval=${interval}&limit=${limit}&offset=${offset}`;

  try {
    const res = await fetch(url);
    const data = await res.json();
    const labels = data.timeline.map(t => t.time);
    const values = data.timeline.map(t => t.anomalies);

    if (chart) chart.destroy();
    const ctx = byId('timelineChart').getContext('2d');
    chart = new Chart(ctx, {
      type: 'line',
      data: {
        labels,
        datasets: [{
          label: `Anomalies (${interval})`,
          data: values,
          fill: false,
          tension: 0.2
        }]
      },
      options: {
        responsive: true,
        scales: { y: { beginAtZero: true } }
      }
    });
  } catch (err) {
    alert('Error loading chart: ' + err.message);
  }
};

const loadCompareChart = async () => {
  const from = parseInt(byId('fromHour').value);
  const to = parseInt(byId('toHour').value);
  const url = `${backendUrl}/api/anomaly_flow_compare?from_hour=${from}&to_hour=${to}`;

  try {
    const res = await fetch(url);
    const data = await res.json();
    if (data.error) throw new Error(data.error);

    const ctx = byId('compareChart').getContext('2d');
    if (window.compareChartObj) window.compareChartObj.destroy();

    window.compareChartObj = new Chart(ctx, {
      type: 'bar',
      data: {
        labels: ['Today', 'Yesterday'],
        datasets: [{
          label: `Anomalies (${data.interval})`,
          data: [data.today.anomalies, data.yesterday.anomalies],
          backgroundColor: ['#e19435', '#0e56ff']
        }]
      },
      options: {
        scales: { y: { beginAtZero: true } }
      }
    });
  } catch (err) {
    alert('Comparison error: ' + err.message);
  }
};

const loadHourlyCompareChart = async () => {
  const from = parseInt(byId('fromHourChart').value);
  const to = parseInt(byId('toHourChart').value);
  const url = `${backendUrl}/api/anomaly_flow_compare_timeline?from_hour=${from}&to_hour=${to}`;

  try {
    const res = await fetch(url);
    const data = await res.json();
    if (data.error) throw new Error(data.error);

    const labels = data.timeline.map(t => t.hour);
    const todayData = data.timeline.map(t => t.today);
    const yesterdayData = data.timeline.map(t => t.yesterday);

    const ctx = byId('hourlyCompareChart').getContext('2d');
    if (window.hourlyCompareChartObj) window.hourlyCompareChartObj.destroy();

    window.hourlyCompareChartObj = new Chart(ctx, {
      type: 'bar',
      data: {
        labels,
        datasets: [
          {
            label: 'Today',
            data: todayData,
            backgroundColor: '#e19435'
          },
          {
            label: 'Yesterday',
            data: yesterdayData,
            backgroundColor: '#0e56ff'
          }
        ]
      },
      options: {
        responsive: true,
        scales: { y: { beginAtZero: true } }
      }
    });
  } catch (err) {
    alert('Error building chart: ' + err.message);
  }
};

// Event listeners
byId('analyzeManual').addEventListener('click', analyzeFlow);
byId('analyzeRedis').addEventListener('click', fetchAndAnalyzeFlows);
byId('exportCSV').addEventListener('click', () => exportAnomalies('csv'));
byId('exportJSON').addEventListener('click', () => exportAnomalies('json'));
byId('timelineBtn').addEventListener('click', loadTimelineChart);
byId('compareBtn').addEventListener('click', loadCompareChart);
byId('hourlyCompareBtn').addEventListener('click', loadHourlyCompareChart);

document.querySelectorAll('th[data-sort]').forEach(th => {
  th.addEventListener('click', () => sortTableBy(th.dataset.sort));
});

const exportAnomalies = (format) => {
  const anomalies = lastEvents.filter(e => e.anomaly);
  if (anomalies.length === 0) return alert('No anomalies for export');

  if (format === 'csv') {
    const headers = Object.keys(anomalies[0]);
    const rows = anomalies.map(e => headers.map(h => JSON.stringify(e[h] ?? '')).join(','));
    const csv = [headers.join(','), ...rows].join('\n');
    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    link.href = URL.createObjectURL(blob);
    link.download = 'anomalies.csv';
    link.click();
  } else {
    const blob = new Blob([JSON.stringify(anomalies, null, 2)], { type: 'application/json' });
    const link = document.createElement('a');
    link.href = URL.createObjectURL(blob);
    link.download = 'anomalies.json';
    link.click();
  }
};

let autoRefreshInterval = null;

const setupAutoRefresh = () => {
  const checkbox = byId('autoRefresh');
  if (!checkbox) return;

  if (autoRefreshInterval) clearInterval(autoRefreshInterval);

  if (checkbox.checked) {
    autoRefreshInterval = setInterval(() => {
      if (checkbox.checked  && hasRecentEvents) {
        fetchAndAnalyzeFlows();
      }
    }, 120000); // 120 sec
  }
};

// when the checkbox state changes, we recreate the interval
const autoCheckbox = byId('autoRefresh');
if (autoCheckbox) {
  autoCheckbox.addEventListener('change', setupAutoRefresh);
}

// Init
loadState();
setupAutoRefresh();
initLanguage();

