{% extends 'base.html' %}
{% load i18n %}

{% block content %}
<script src="https://cdn.jsdelivr.net/npm/echarts@5.6.0/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/topojson-client@3/dist/topojson-client.min.js"></script>

<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 space-y-6">

  <!-- Header -->
  <div class="flex items-center justify-between flex-wrap gap-3">
    <div>
      <h1 class="text-2xl font-bold text-gray-900 flex items-center gap-2">
        <i class="fas fa-router text-indigo-500"></i>
        Router DNS Monitor
        <span class="inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full
                     {% if settings.enabled %}bg-green-100 text-green-700 animate-pulse{% else %}bg-gray-100 text-gray-500{% endif %}">
          <span class="w-1.5 h-1.5 rounded-full inline-block {% if settings.enabled %}bg-green-500{% else %}bg-gray-400{% endif %}"></span>
          {% if settings.enabled %}Live{% else %}Paused{% endif %}
        </span>
      </h1>
      <p class="text-sm text-gray-400 mt-0.5">
        ASUS GT-AX6000 · dnsmasq syslog · UDP :{{ settings.syslog_port }}
      </p>
      <div class="mt-1 flex items-center gap-2 text-xs text-gray-400">
        <span id="status-last">{% if settings.last_received_at %}Last: {{ settings.last_received_at|timesince }} ago{% else %}No data yet{% endif %}</span>
        <span>·</span>
        <span id="status-total">—</span>
      </div>
    </div>
    <div class="flex flex-col items-end gap-2">
      <!-- Time range selector -->
      <div class="flex items-center gap-1 bg-gray-100 rounded-lg p-1">
        {% for rkey, rlabel in all_ranges %}
        <a href="?range={{ rkey }}"
           class="px-2.5 py-1 text-xs rounded-md font-medium transition-colors
                  {% if rkey == current_range %}bg-white text-gray-900 shadow-sm{% else %}text-gray-500 hover:text-gray-700{% endif %}">
          {{ rlabel|slice:"5:" }}
        </a>
        {% endfor %}
      </div>
      <div class="flex items-center gap-2 flex-wrap justify-end">
        <button id="toggle-btn"
                onclick="toggleReceiver()"
                class="inline-flex items-center px-3 py-1.5 text-xs rounded-md font-medium transition-colors
                       {% if settings.enabled %}bg-green-100 text-green-700 hover:bg-green-200{% else %}bg-gray-200 text-gray-500 hover:bg-gray-300{% endif %}">
          <span id="toggle-dot" class="w-1.5 h-1.5 rounded-full mr-1.5 {% if settings.enabled %}bg-green-500{% else %}bg-gray-400{% endif %}"></span>
          <span id="toggle-label">{% if settings.enabled %}Receiving{% else %}Paused{% endif %}</span>
        </button>
        <a href="{% url 'routermon-settings' %}"
           class="inline-flex items-center px-3 py-1.5 bg-gray-100 text-gray-600 text-xs rounded-md hover:bg-gray-200">
          <i class="fas fa-cog mr-1.5"></i> Settings
        </a>
      </div>
    </div>
  </div>

  <!-- Messages -->
  {% for msg in messages %}
  <div class="px-4 py-2 rounded-md text-sm border
    {% if msg.tags == 'success' %}bg-green-50 text-green-800 border-green-200
    {% elif msg.tags == 'error' %}bg-red-50 text-red-800 border-red-200
    {% else %}bg-blue-50 text-blue-800 border-blue-200{% endif %}">
    {{ msg }}
  </div>
  {% endfor %}

  <!-- Stats row -->
  <div class="grid grid-cols-2 sm:grid-cols-5 gap-4">
    {% with s=stats %}
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-4">
      <div class="text-xs text-gray-400 font-medium uppercase tracking-wide mb-1">DNS Queries</div>
      <div class="text-2xl font-bold text-gray-900">{{ s.total }}</div>
    </div>
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-4">
      <div class="text-xs text-gray-400 font-medium uppercase tracking-wide mb-1">Unique Domains</div>
      <div class="text-2xl font-bold text-gray-900">{{ s.unique_domains }}</div>
    </div>
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-4">
      <div class="text-xs text-gray-400 font-medium uppercase tracking-wide mb-1">Devices</div>
      <div class="text-2xl font-bold text-gray-900">{{ s.unique_clients }}</div>
    </div>
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-4">
      <div class="text-xs text-gray-400 font-medium uppercase tracking-wide mb-1">NXDOMAIN</div>
      <div class="text-2xl font-bold {% if s.nxdomain_count %}text-red-600{% else %}text-gray-900{% endif %}">
        {{ s.nxdomain_count }}
      </div>
    </div>
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-4">
      <div class="text-xs text-gray-400 font-medium uppercase tracking-wide mb-1">NX Rate</div>
      <div class="text-2xl font-bold {% if s.nxdomain_pct > 10 %}text-orange-500{% else %}text-gray-900{% endif %}">
        {{ s.nxdomain_pct }}%
      </div>
    </div>
    {% endwith %}
  </div>

  <!-- Charts row -->
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
    <!-- Query volume timeline -->
    <div class="lg:col-span-2 bg-white rounded-lg shadow-sm border border-gray-100 p-4">
      <div class="text-sm font-semibold text-gray-700 mb-3" id="chart-title">{{ range_label }}</div>
      <div id="timelineChart" style="height:220px;"></div>
    </div>
    <!-- Top domains mini chart -->
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-4">
      <div class="text-sm font-semibold text-gray-700 mb-3">Top Domains — {{ range_label }}</div>
      <div id="domainsChart" style="height:220px;"></div>
    </div>
  </div>

  <!-- Geo map -->
  <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-4">
    <div class="flex items-center justify-between mb-3 flex-wrap gap-2">
      <div class="text-sm font-semibold text-gray-700">Resolved IP Geography — {{ range_label }}</div>
      <div id="geo-legend" class="flex items-center gap-3 text-xs text-gray-400 flex-wrap"></div>
    </div>
    <div id="geoMap" class="w-full" style="height:320px; position:relative; overflow:hidden;"></div>
  </div>

  <!-- Top tables -->
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
    <!-- Top domains -->
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 overflow-hidden">
      <div class="px-4 py-3 border-b border-gray-100 text-sm font-semibold text-gray-700">
        Top Queried Domains — {{ range_label }}
      </div>
      <table class="w-full text-xs">
        <thead class="bg-gray-50 text-gray-500">
          <tr>
            <th class="px-3 py-2 text-left">Domain</th>
            <th class="px-3 py-2 text-left">Country</th>
            <th class="px-3 py-2 text-right">Queries</th>
            <th class="px-3 py-2 text-right">NX</th>
          </tr>
        </thead>
        <tbody class="divide-y divide-gray-50">
          {% for d in top_domains %}
          <tr class="hover:bg-gray-50">
            <td class="px-3 py-2 font-mono text-gray-800 truncate max-w-[200px]">
              <button class="text-indigo-600 hover:underline font-mono text-left truncate max-w-full"
                      onclick="setQueryFilter('domain','{{ d.domain|escapejs }}')">{{ d.domain }}</button>
            </td>
            <td class="px-3 py-2 text-gray-500">
              {% if d.country %}
                {% if d.country_code %}<span class="mr-1">{{ d.country_code }}</span>{% endif %}
                {{ d.country }}
              {% else %}—{% endif %}
            </td>
            <td class="px-3 py-2 text-right font-medium">{{ d.count }}</td>
            <td class="px-3 py-2 text-right {% if d.nxcount %}text-red-500{% else %}text-gray-400{% endif %}">
              {{ d.nxcount }}</td>
          </tr>
          {% empty %}
          <tr><td colspan="4" class="px-3 py-6 text-center text-gray-400">No data yet</td></tr>
          {% endfor %}
        </tbody>
      </table>
    </div>

    <!-- Top clients -->
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 overflow-hidden">
      <div class="px-4 py-3 border-b border-gray-100 text-sm font-semibold text-gray-700">
        Top Clients — {{ range_label }}
      </div>
      <table class="w-full text-xs">
        <thead class="bg-gray-50 text-gray-500">
          <tr>
            <th class="px-3 py-2 text-left">Client</th>
            <th class="px-3 py-2 text-left">Hostname</th>
            <th class="px-3 py-2 text-right">Queries</th>
            <th class="px-3 py-2 text-right">NX</th>
          </tr>
        </thead>
        <tbody class="divide-y divide-gray-50">
          {% for c in top_clients %}
          <tr class="hover:bg-gray-50">
            <td class="px-3 py-2 font-mono text-gray-800">
              <button class="text-indigo-600 hover:underline font-mono"
                      onclick="setQueryFilter('client','{{ c.client_ip|escapejs }}')">{{ c.client_ip }}</button>
            </td>
            <td class="px-3 py-2 text-gray-500">{{ c.hostname|default:"—" }}</td>
            <td class="px-3 py-2 text-right font-medium">{{ c.count }}</td>
            <td class="px-3 py-2 text-right {% if c.nxcount %}text-red-500{% else %}text-gray-400{% endif %}">
              {{ c.nxcount }}</td>
          </tr>
          {% empty %}
          <tr><td colspan="4" class="px-3 py-6 text-center text-gray-400">No data yet</td></tr>
          {% endfor %}
        </tbody>
      </table>
    </div>
  </div>

  <!-- Live DNS query stream -->
  <div class="bg-white rounded-lg shadow-sm border border-gray-100 overflow-hidden">
    <div class="px-4 py-3 border-b border-gray-100 flex items-center justify-between flex-wrap gap-2">
      <div class="text-sm font-semibold text-gray-700">Live DNS Queries</div>
      <!-- Filter controls -->
      <div class="flex items-center gap-2 flex-wrap text-xs" id="query-filters">
        <input type="text" id="filter-client" placeholder="Client IP / hostname" class="border border-gray-200 rounded px-2 py-1 text-xs w-36 focus:outline-none focus:ring-1 focus:ring-indigo-300"
               oninput="reloadQueries()">
        <input type="text" id="filter-domain" placeholder="Domain" class="border border-gray-200 rounded px-2 py-1 text-xs w-40 focus:outline-none focus:ring-1 focus:ring-indigo-300"
               oninput="reloadQueries()">
        <select id="filter-type" class="border border-gray-200 rounded px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-indigo-300"
                onchange="reloadQueries()">
          <option value="">All types</option>
          <option value="A">A</option>
          <option value="AAAA">AAAA</option>
          <option value="PTR">PTR</option>
          <option value="TXT">TXT</option>
          <option value="MX">MX</option>
          <option value="SRV">SRV</option>
          <option value="HTTPS">HTTPS</option>
        </select>
        <label class="flex items-center gap-1 cursor-pointer">
          <input type="checkbox" id="filter-nxdomain" onchange="reloadQueries()">
          <span class="text-red-600 font-medium">NXDOMAIN only</span>
        </label>
        <button onclick="clearFilters()" class="text-gray-400 hover:text-gray-600 text-xs">✕ Clear</button>
      </div>
    </div>

    <div id="queries-container"
         hx-get="{% url 'routermon-queries-partial' %}"
         hx-trigger="load, every 10s"
         hx-swap="innerHTML">
      <div class="px-4 py-6 text-center text-gray-400 text-sm">Loading…</div>
    </div>
  </div>

  <!-- WAN Incoming Events -->
  <div class="bg-white rounded-lg shadow-sm border border-gray-100 overflow-hidden">
    <div class="px-4 py-3 border-b border-gray-100 flex items-center justify-between flex-wrap gap-2">
      <div class="flex items-center gap-3">
        <div class="text-sm font-semibold text-gray-700">WAN Incoming Attempts</div>
        <span class="text-xs text-gray-400 bg-gray-100 rounded-full px-2 py-0.5">Last 24h: <strong class="text-rose-600">{{ wan_total_24h }}</strong></span>
      </div>
      <div class="flex items-center gap-2 flex-wrap text-xs">
        <input type="text" id="wan-filter-src" placeholder="Source IP" class="border border-gray-200 rounded px-2 py-1 text-xs w-32 focus:outline-none focus:ring-1 focus:ring-rose-300"
               oninput="reloadWan()">
        <input type="text" id="wan-filter-port" placeholder="Dst port" class="border border-gray-200 rounded px-2 py-1 text-xs w-24 focus:outline-none focus:ring-1 focus:ring-rose-300"
               oninput="reloadWan()">
        <select id="wan-filter-proto" class="border border-gray-200 rounded px-2 py-1 text-xs focus:outline-none focus:ring-1 focus:ring-rose-300" onchange="reloadWan()">
          <option value="">All proto</option>
          <option value="TCP">TCP</option>
          <option value="UDP">UDP</option>
          <option value="ICMP">ICMP</option>
        </select>
        <input type="text" id="wan-filter-country" placeholder="Country" class="border border-gray-200 rounded px-2 py-1 text-xs w-24 focus:outline-none focus:ring-1 focus:ring-rose-300"
               oninput="reloadWan()">
        <button onclick="clearWanFilters()" class="text-gray-400 hover:text-gray-600 text-xs">✕ Clear</button>
      </div>
    </div>

    <!-- WAN timeline chart -->
    <div class="px-4 pt-3">
      <div id="wanTimelineChart" style="height:140px;"></div>
    </div>

    <!-- Top attacked ports (mini bar chart) -->
    <div class="px-4 pt-3 grid grid-cols-1 md:grid-cols-2 gap-4">
      <div>
        <div class="text-xs font-medium text-gray-500 mb-2">Top Targeted Ports (24h)</div>
        <div id="wanPortsChart" style="height:180px;"></div>
      </div>
      <div>
        <div class="text-xs font-medium text-gray-500 mb-2">Top Source IPs (24h)</div>
        <table class="w-full text-xs">
          <thead class="text-gray-400">
            <tr>
              <th class="text-left pb-1">Source IP</th>
              <th class="text-right pb-1">Hits</th>
              <th class="text-left pb-1 pl-2">Country</th>
            </tr>
          </thead>
          <tbody class="divide-y divide-gray-50">
            {% for s in top_wan_sources %}
            <tr class="hover:bg-gray-50">
              <td class="py-1 font-mono">
                <button class="text-rose-600 hover:underline" onclick="setWanFilter('src_ip','{{ s.src_ip|escapejs }}')">{{ s.src_ip }}</button>
              </td>
              <td class="py-1 text-right font-medium">{{ s.count }}</td>
              <td class="py-1 pl-2 text-gray-500">{{ s.country_code }}{% if s.country %} {{ s.country }}{% endif %}</td>
            </tr>
            {% empty %}
            <tr><td colspan="3" class="py-4 text-center text-gray-400">No data yet</td></tr>
            {% endfor %}
          </tbody>
        </table>
      </div>
    </div>

    <!-- WAN geo map -->
    <div class="px-4 pt-3 pb-2">
      <div class="flex items-center justify-between mb-2 flex-wrap gap-2">
        <div class="text-xs font-medium text-gray-500">Source Geography — {{ range_label }}</div>
        <div id="wan-geo-legend" class="flex items-center gap-3 text-xs text-gray-400 flex-wrap"></div>
      </div>
      <div id="wanGeoMap" class="w-full" style="height:420px; position:relative; overflow:hidden;"></div>
    </div>

    <!-- Live WAN event table -->
    <div id="wan-container"
         class="overflow-x-auto"
         hx-get="{% url 'routermon-wan-partial' %}"
         hx-trigger="load, every 15s"
         hx-swap="innerHTML">
      <div class="px-4 py-6 text-center text-gray-400 text-sm">Loading…</div>
    </div>
  </div>

</div>

<script>
// ── SSE status stream ─────────────────────────────────────────────────────────
const statusEs = new EventSource("{% url 'routermon-status' %}");
statusEs.onmessage = (e) => {
  const d = JSON.parse(e.data);
  document.getElementById('status-total').textContent = d.total_queries.toLocaleString() + ' total queries';
  if (d.last_received_at) {
    const dt = new Date(d.last_received_at);
    const ago = Math.round((Date.now() - dt.getTime()) / 1000);
    document.getElementById('status-last').textContent = 'Last: ' + (ago < 60 ? ago + 's' : Math.round(ago/60) + 'm') + ' ago';
  }
};

// ── Toggle receiver ───────────────────────────────────────────────────────────
async function toggleReceiver() {
  const btn = document.getElementById('toggle-btn');
  btn.disabled = true;
  const res = await fetch("{% url 'routermon-toggle' %}", {
    method: 'POST',
    headers: {'X-CSRFToken': '{{ csrf_token }}'},
  });
  const data = await res.json();
  const dot = document.getElementById('toggle-dot');
  const label = document.getElementById('toggle-label');
  if (data.enabled) {
    btn.className = btn.className.replace(/bg-gray-\w+ text-gray-\w+ hover:bg-gray-\w+/, 'bg-green-100 text-green-700 hover:bg-green-200');
    dot.className = dot.className.replace('bg-gray-400', 'bg-green-500');
    label.textContent = 'Receiving';
  } else {
    btn.className = btn.className.replace(/bg-green-\w+ text-green-\w+ hover:bg-green-\w+/, 'bg-gray-200 text-gray-500 hover:bg-gray-300');
    dot.className = dot.className.replace('bg-green-500', 'bg-gray-400');
    label.textContent = 'Paused';
  }
  btn.disabled = false;
}

// ── Live queries HTMX helpers ─────────────────────────────────────────────────
function setQueryFilter(field, value) {
  if (field === 'client') document.getElementById('filter-client').value = value;
  if (field === 'domain') document.getElementById('filter-domain').value = value;
  reloadQueries();
  document.getElementById('queries-container').scrollIntoView({behavior: 'smooth', block: 'nearest'});
}

function clearFilters() {
  document.getElementById('filter-client').value = '';
  document.getElementById('filter-domain').value = '';
  document.getElementById('filter-type').value = '';
  document.getElementById('filter-nxdomain').checked = false;
  reloadQueries();
}

let _reloadTimer = null;
function reloadQueries() {
  clearTimeout(_reloadTimer);
  _reloadTimer = setTimeout(() => {
    const client = document.getElementById('filter-client').value.trim();
    const domain = document.getElementById('filter-domain').value.trim();
    const type   = document.getElementById('filter-type').value;
    const nx     = document.getElementById('filter-nxdomain').checked ? '1' : '';
    const params = new URLSearchParams();
    if (client) params.set('client', client);
    if (domain) params.set('domain', domain);
    if (type)   params.set('type', type);
    if (nx)     params.set('nxdomain', nx);
    const url = "{% url 'routermon-queries-partial' %}" + (params.toString() ? '?' + params.toString() : '');
    htmx.ajax('GET', url, '#queries-container');
  }, 300);
}

// ── Timeline chart ────────────────────────────────────────────────────────────
const timelineChart = echarts.init(document.getElementById('timelineChart'));
const domainsChartEl = echarts.init(document.getElementById('domainsChart'));

async function loadChart() {
  const range = '{{ current_range }}';
  const res = await fetch("{% url 'routermon-chart' %}?range=" + range);
  const d = await res.json();

  timelineChart.setOption({
    tooltip: {trigger: 'axis'},
    legend: {data: ['Queries', 'NXDOMAIN'], textStyle: {fontSize: 11}},
    grid: {left: '3%', right: '3%', bottom: '3%', containLabel: true},
    xAxis: {type: 'category', data: d.labels, axisLabel: {fontSize: 10}},
    yAxis: {type: 'value', axisLabel: {fontSize: 10}},
    series: [
      {name: 'Queries', type: 'bar', data: d.total, itemStyle: {color: '#6366f1'}, barMaxWidth: 20},
      {name: 'NXDOMAIN', type: 'bar', data: d.nxcount, itemStyle: {color: '#ef4444'}, barMaxWidth: 20},
    ],
  });

  // Top domains mini bar chart
  const topData = {{ top_domains_json|safe }};
  const top10 = topData.slice(0, 10).reverse();
  domainsChartEl.setOption({
    tooltip: {trigger: 'axis', axisPointer: {type: 'shadow'}},
    grid: {left: '3%', right: '8%', bottom: '3%', containLabel: true},
    xAxis: {type: 'value', axisLabel: {fontSize: 9}},
    yAxis: {type: 'category', data: top10.map(d => d.domain.length > 22 ? d.domain.slice(0, 22) + '…' : d.domain),
            axisLabel: {fontSize: 9}},
    series: [{
      type: 'bar', data: top10.map(d => d.count),
      itemStyle: {color: '#818cf8'},
      barMaxWidth: 16,
    }],
  });
}

loadChart();
window.addEventListener('resize', () => { timelineChart.resize(); domainsChartEl.resize(); });

// ── Geo map ───────────────────────────────────────────────────────────────────
async function loadGeoMap() {
  const range = '{{ current_range }}';
  const [geoRes, worldRes] = await Promise.all([
    fetch("{% url 'routermon-geo' %}?range=" + range),
    fetch('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json'),
  ]);
  const geo = await geoRes.json();
  const world = await worldRes.json();

  const container = document.getElementById('geoMap');
  const w = container.clientWidth, h = container.clientHeight;
  const svg = d3.select('#geoMap').append('svg').attr('width', w).attr('height', h);
  const proj = d3.geoNaturalEarth1().scale(w / 6.3).translate([w / 2, h / 2]);
  const path = d3.geoPath(proj);
  const countries = topojson.feature(world, world.objects.countries);

  // Country colour scale
  const countMap = Object.fromEntries((geo.countries || []).map(c => [c.country_code, c.total]));
  const maxCount = Math.max(...Object.values(countMap), 1);
  const colour = d3.scaleSequential(d3.interpolateBlues).domain([0, maxCount]);

  svg.append('g').selectAll('path')
    .data(countries.features)
    .join('path')
    .attr('d', path)
    .attr('fill', f => {
      const iso = String(f.id).padStart(3, '0');
      // world-atlas uses ISO 3166-1 numeric; we have alpha-2 — best effort match
      return '#e5e7eb';
    })
    .attr('stroke', '#d1d5db').attr('stroke-width', 0.4);

  // Country highlights using geo data
  (geo.countries || []).forEach(c => {
    // We'll overlay circles on the bubbles instead of colour fills (alpha-2 ↔ numeric mapping is complex)
  });

  // Bubble circles for resolved IPs
  const maxBubble = Math.max(...(geo.bubbles || []).map(b => b.total), 1);
  const rScale = d3.scaleSqrt().domain([1, maxBubble]).range([2, 22]);

  svg.append('g').selectAll('circle')
    .data(geo.bubbles || [])
    .join('circle')
    .attr('cx', b => proj([b.lon, b.lat])[0])
    .attr('cy', b => proj([b.lon, b.lat])[1])
    .attr('r', b => rScale(b.total))
    .attr('fill', '#6366f1')
    .attr('fill-opacity', 0.55)
    .attr('stroke', '#4f46e5')
    .attr('stroke-width', 0.8)
    .append('title')
    .text(b => `${b.label}: ${b.total} queries`);

  // Legend
  const legend = document.getElementById('geo-legend');
  (geo.countries || []).slice(0, 5).forEach(c => {
    const span = document.createElement('span');
    span.className = 'flex items-center gap-1';
    span.innerHTML = `<span class="w-2 h-2 rounded-full bg-indigo-400 inline-block"></span>${c.country} (${c.total})`;
    legend.appendChild(span);
  });
}

loadGeoMap();

// ── WAN events ────────────────────────────────────────────────────────────────
const wanTimelineChart = echarts.init(document.getElementById('wanTimelineChart'));
const wanPortsChart = echarts.init(document.getElementById('wanPortsChart'));

async function loadWanChart() {
  const range = '{{ current_range }}';
  const res = await fetch("{% url 'routermon-wan-chart' %}?range=" + range);
  const d = await res.json();
  wanTimelineChart.setOption({
    tooltip: {trigger: 'axis'},
    grid: {left: '3%', right: '3%', top: '10%', bottom: '8%', containLabel: true},
    xAxis: {type: 'category', data: d.labels, axisLabel: {fontSize: 9}},
    yAxis: {type: 'value', axisLabel: {fontSize: 9}},
    series: [{name: 'WAN attempts', type: 'bar', data: d.total, itemStyle: {color: '#f43f5e'}, barMaxWidth: 20}],
  });
}

const portsData = {{ top_attacked_ports_json|safe }};
const top10Ports = portsData.slice(0, 10).reverse();
wanPortsChart.setOption({
  tooltip: {trigger: 'axis', axisPointer: {type: 'shadow'}},
  grid: {left: '3%', right: '8%', bottom: '3%', containLabel: true},
  xAxis: {type: 'value', axisLabel: {fontSize: 9}},
  yAxis: {
    type: 'category',
    data: top10Ports.map(d => d.dst_port + '/' + d.protocol),
    axisLabel: {fontSize: 9},
  },
  series: [{type: 'bar', data: top10Ports.map(d => d.count), itemStyle: {color: '#fb7185'}, barMaxWidth: 16}],
});

loadWanChart();
window.addEventListener('resize', () => { wanTimelineChart.resize(); wanPortsChart.resize(); });

// ── WAN geo map ───────────────────────────────────────────────────────────────
async function loadWanGeoMap() {
  const range = '{{ current_range }}';
  const [geoRes, worldRes] = await Promise.all([
    fetch("{% url 'routermon-wan-geo' %}?range=" + range),
    fetch('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json'),
  ]);
  const geo = await geoRes.json();
  const world = await worldRes.json();

  const container = document.getElementById('wanGeoMap');
  const w = container.clientWidth, h = container.clientHeight;
  const svg = d3.select('#wanGeoMap').append('svg').attr('width', w).attr('height', h);
  const proj = d3.geoNaturalEarth1().scale(w / 6.3).translate([w / 2, h / 2]);
  const path = d3.geoPath(proj);
  const countries = topojson.feature(world, world.objects.countries);

  const countMap = Object.fromEntries((geo.countries || []).map(c => [c.country_code, c.total]));
  const maxCount = Math.max(...Object.values(countMap), 1);
  const colour = d3.scaleSequential(d3.interpolateReds).domain([0, maxCount]);

  // Build numeric→alpha2 lookup using the same table from the DNS map
  const alpha2Num = {"AF":"004","AX":"008","AL":"008","DZ":"012","AS":"016","AD":"020","AO":"024","AI":"660","AQ":"010","AG":"028","AR":"032","AM":"051","AW":"533","AU":"036","AT":"040","AZ":"031","BS":"044","BH":"048","BD":"050","BB":"052","BY":"112","BE":"056","BZ":"084","BJ":"204","BM":"060","BT":"064","BO":"068","BA":"070","BW":"072","BV":"074","BR":"076","IO":"086","BN":"096","BG":"100","BF":"854","BI":"108","CV":"132","KH":"116","CM":"120","CA":"124","KY":"136","CF":"140","TD":"148","CL":"152","CN":"156","CX":"162","CC":"166","CO":"170","KM":"174","CG":"178","CD":"180","CK":"184","CR":"188","CI":"384","HR":"191","CU":"192","CW":"531","CY":"196","CZ":"203","DK":"208","DJ":"262","DM":"212","DO":"214","EC":"218","EG":"818","SV":"222","GQ":"226","ER":"232","EE":"233","SZ":"748","ET":"231","FK":"238","FO":"234","FJ":"242","FI":"246","FR":"250","GF":"254","PF":"258","TF":"260","GA":"266","GM":"270","GE":"268","DE":"276","GH":"288","GI":"292","GR":"300","GL":"304","GD":"308","GP":"312","GU":"316","GT":"320","GG":"831","GN":"324","GW":"624","GY":"328","HT":"332","HM":"334","VA":"336","HN":"340","HK":"344","HU":"348","IS":"352","IN":"356","ID":"360","IR":"364","IQ":"368","IE":"372","IM":"833","IL":"376","IT":"380","JM":"388","JP":"392","JE":"832","JO":"400","KZ":"398","KE":"404","KI":"296","KP":"408","KR":"410","KW":"414","KG":"417","LA":"418","LV":"428","LB":"422","LS":"426","LR":"430","LY":"434","LI":"438","LT":"440","LU":"442","MO":"446","MG":"450","MW":"454","MY":"458","MV":"462","ML":"466","MT":"470","MH":"584","MQ":"474","MR":"478","MU":"480","YT":"175","MX":"484","FM":"583","MD":"498","MC":"492","MN":"496","ME":"499","MS":"500","MA":"504","MZ":"508","MM":"104","NA":"516","NR":"520","NP":"524","NL":"528","NC":"540","NZ":"554","NI":"558","NE":"562","NG":"566","NU":"570","NF":"574","MK":"807","MP":"580","NO":"578","OM":"512","PK":"586","PW":"585","PS":"275","PA":"591","PG":"598","PY":"600","PE":"604","PH":"608","PN":"612","PL":"616","PT":"620","PR":"630","QA":"634","RE":"638","RO":"642","RU":"643","RW":"646","BL":"652","SH":"654","KN":"659","LC":"662","MF":"663","PM":"666","VC":"670","WS":"882","SM":"674","ST":"678","SA":"682","SN":"686","RS":"688","SC":"690","SL":"694","SG":"702","SX":"534","SK":"703","SI":"705","SB":"090","SO":"706","ZA":"710","GS":"239","SS":"728","ES":"724","LK":"144","SD":"729","SR":"740","SJ":"744","SE":"752","CH":"756","SY":"760","TW":"158","TJ":"762","TZ":"834","TH":"764","TL":"626","TG":"768","TK":"772","TO":"776","TT":"780","TN":"788","TR":"792","TM":"795","TC":"796","TV":"798","UG":"800","UA":"804","AE":"784","GB":"826","US":"840","UM":"581","UY":"858","UZ":"860","VU":"548","VE":"862","VN":"704","VG":"092","VI":"850","WF":"876","EH":"732","YE":"887","ZM":"894","ZW":"716"};
  const numAlpha2 = Object.fromEntries(Object.entries(alpha2Num).map(([a2, num]) => [num, a2]));

  svg.append('g').selectAll('path')
    .data(countries.features)
    .join('path')
    .attr('d', path)
    .attr('fill', f => {
      const num = String(f.id).padStart(3, '0');
      const a2 = numAlpha2[num];
      const cnt = a2 ? countMap[a2] : 0;
      return cnt ? colour(cnt) : '#e5e7eb';
    })
    .attr('stroke', '#d1d5db').attr('stroke-width', 0.4)
    .append('title').text(f => {
      const num = String(f.id).padStart(3, '0');
      const a2 = numAlpha2[num];
      const cnt = a2 ? countMap[a2] : 0;
      return cnt ? `${a2}: ${cnt} attempts` : '';
    });

  // Bubble circles for source IP locations
  const maxBubble = Math.max(...(geo.bubbles || []).map(b => b.total), 1);
  const rScale = d3.scaleSqrt().domain([1, maxBubble]).range([3, 24]);

  svg.append('g').selectAll('circle')
    .data(geo.bubbles || [])
    .join('circle')
    .attr('cx', b => proj([b.lon, b.lat])[0])
    .attr('cy', b => proj([b.lon, b.lat])[1])
    .attr('r', b => rScale(b.total))
    .attr('fill', '#f43f5e')
    .attr('fill-opacity', 0.55)
    .attr('stroke', '#e11d48')
    .attr('stroke-width', 0.8)
    .append('title')
    .text(b => `${b.label}: ${b.total} attempts`);

  // Legend
  const legend = document.getElementById('wan-geo-legend');
  (geo.countries || []).slice(0, 5).forEach(c => {
    const span = document.createElement('span');
    span.className = 'flex items-center gap-1';
    span.innerHTML = `<span class="w-2 h-2 rounded-full bg-rose-400 inline-block"></span>${c.country || c.country_code} (${c.total})`;
    legend.appendChild(span);
  });
}

loadWanGeoMap();

function setWanFilter(field, value) {
  if (field === 'src_ip') document.getElementById('wan-filter-src').value = value;
  if (field === 'dst_port') document.getElementById('wan-filter-port').value = value;
  reloadWan();
  document.getElementById('wan-container').scrollIntoView({behavior: 'smooth', block: 'nearest'});
}

function clearWanFilters() {
  document.getElementById('wan-filter-src').value = '';
  document.getElementById('wan-filter-port').value = '';
  document.getElementById('wan-filter-proto').value = '';
  document.getElementById('wan-filter-country').value = '';
  reloadWan();
}

let _wanTimer = null;
function reloadWan() {
  clearTimeout(_wanTimer);
  _wanTimer = setTimeout(() => {
    const params = new URLSearchParams();
    const src = document.getElementById('wan-filter-src').value.trim();
    const port = document.getElementById('wan-filter-port').value.trim();
    const proto = document.getElementById('wan-filter-proto').value;
    const country = document.getElementById('wan-filter-country').value.trim();
    if (src) params.set('src_ip', src);
    if (port) params.set('dst_port', port);
    if (proto) params.set('protocol', proto);
    if (country) params.set('country', country);
    const url = "{% url 'routermon-wan-partial' %}" + (params.toString() ? '?' + params.toString() : '');
    htmx.ajax('GET', url, '#wan-container');
  }, 300);
}
</script>
{% endblock %}
