{% extends 'base.html' %}

{% 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-eye text-indigo-500"></i>
        Nginx Monitor
        <span class="inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full
                     bg-green-100 text-green-700 animate-pulse">
          <span class="w-1.5 h-1.5 rounded-full bg-green-500 inline-block"></span> Live
        </span>
      </h1>
      <p class="text-sm text-gray-400 mt-0.5 font-mono truncate max-w-xs sm:max-w-sm md:max-w-lg" title="{{ nginx_settings.source_display }}">{{ nginx_settings.source_display }}</p>
      <div class="mt-1 flex items-center gap-2 text-xs text-gray-400">
        <span id="ingest-last-fetch">{% if nginx_settings.last_fetch_at %}Last: {{ nginx_settings.last_fetch_at|timesince }} ago{% else %}No ingestion yet{% endif %}</span>
        <span>·</span>
        <span id="ingest-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>
      <!-- Active filters chips -->
      <div id="active-filters" class="flex items-center gap-1.5 flex-wrap justify-end min-h-[1.25rem]"></div>
      <div class="flex items-center gap-2 flex-wrap justify-end">
        <button id="ingest-toggle"
                onclick="toggleIngestion()"
                class="inline-flex items-center px-3 py-1.5 text-xs rounded-md font-medium transition-colors {% if nginx_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 nginx_settings.enabled %}bg-green-500{% else %}bg-gray-400{% endif %}"></span>
          <span id="toggle-label">{% if nginx_settings.enabled %}Ingestion On{% else %}Ingestion Off{% endif %}</span>
        </button>
        <form method="post" action="{% url 'nginxmon-fetch' %}">
          {% csrf_token %}
          <button type="submit" class="inline-flex items-center px-3 py-1.5 bg-indigo-100 text-indigo-700 text-xs rounded-md hover:bg-indigo-200 font-medium">
            <i class="fas fa-sync-alt mr-1.5"></i> Fetch Now
          </button>
        </form>
        <form method="post" action="{% url 'nginxmon-detect' %}">
          {% csrf_token %}
          <button type="submit" class="inline-flex items-center px-3 py-1.5 bg-yellow-100 text-yellow-700 text-xs rounded-md hover:bg-yellow-200 font-medium">
            <i class="fas fa-search mr-1.5"></i> Detect Threats
          </button>
        </form>
        <button onclick="document.getElementById('ip-ban-modal').classList.remove('hidden')"
                class="inline-flex items-center px-3 py-1.5 bg-red-600 text-white text-xs rounded-md hover:bg-red-700 font-medium">
          <i class="fas fa-ban mr-1.5"></i> Ban IP
        </button>
        <a href="{% url 'nginxmon-profile-create' %}"
           class="inline-flex items-center px-3 py-1.5 bg-indigo-600 text-white text-xs rounded-md hover:bg-indigo-700 font-medium">
          <i class="fas fa-plus mr-1.5"></i> New Alert Profile
        </a>
        <a href="{% url 'nginxmon-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-4 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">Requests</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">Errors</div>
      <div class="text-2xl font-bold {% if s.errors %}text-red-600{% else %}text-gray-900{% endif %}">{{ s.errors }}</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 IPs</div>
      <div class="text-2xl font-bold text-gray-900">{{ s.unique_ips }}</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">Avg Response</div>
      <div class="text-2xl font-bold text-gray-900">{{ s.avg_resp_ms }} ms</div>
    </div>
    {% endwith %}
  </div>

  <!-- Charts -->
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
    <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>
    <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">Status codes — {{ range_label }}</div>
      <div id="statusChart" style="height:220px;"></div>
    </div>
  </div>

  <!-- Top paths 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 Paths — {{ range_label }}</div>
    <div id="pathsChart" style="height:300px;"></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">Traffic by Region — {{ 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:340px; position:relative; overflow:hidden;"></div>
  </div>

  <!-- Top tables -->
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
    <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 IPs — {{ 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">IP</th>
            <th class="px-3 py-2 text-left">Location</th>
            <th class="px-3 py-2 text-right">Reqs</th>
            <th class="px-3 py-2 text-right">Errors</th>
          </tr>
        </thead>
        <tbody class="divide-y divide-gray-50">
          {% for ip in top_ips %}
          <tr class="hover:bg-gray-50">
            <td class="px-3 py-2 font-mono">
              <button class="text-indigo-600 hover:underline font-mono" onclick="setFilter('ip','{{ ip.remote_addr }}')">{{ ip.remote_addr }}</button>
            </td>
            <td class="px-3 py-2 text-gray-500">
              {% if ip.city or ip.country %}{{ ip.city }}{% if ip.city and ip.country %}, {% endif %}{{ ip.country }}{% else %}—{% endif %}
            </td>
            <td class="px-3 py-2 text-right font-medium">{{ ip.count }}</td>
            <td class="px-3 py-2 text-right {% if ip.errors %}text-red-600{% else %}text-gray-400{% endif %}">{{ ip.errors }}</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 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 Services — {{ 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">Service</th>
            <th class="px-3 py-2 text-right">Requests</th>
          </tr>
        </thead>
        <tbody class="divide-y divide-gray-50">
          {% for svc in top_services %}
          <tr class="hover:bg-gray-50">
            <td class="px-3 py-2 font-mono text-gray-700">
              {% if svc.service %}<button class="text-indigo-600 hover:underline font-mono" onclick="setFilter('service','{{ svc.service|escapejs }}')">{{ svc.service }}</button>{% else %}—{% endif %}
            </td>
            <td class="px-3 py-2 text-right font-medium">{{ svc.count }}</td>
          </tr>
          {% empty %}
          <tr><td colspan="2" class="px-3 py-6 text-center text-gray-400">No data yet</td></tr>
          {% endfor %}
        </tbody>
      </table>
    </div>
  </div>

  <!-- Alert profiles -->
  {% if profiles %}
  <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">
      <div class="text-sm font-semibold text-gray-700">Alert Profiles</div>
      <a href="{% url 'nginxmon-profile-create' %}" class="text-xs text-indigo-600 hover:underline">+ New</a>
    </div>
    <div class="divide-y divide-gray-50">
      {% for p in profiles %}
      <div class="px-4 py-3 flex items-center justify-between text-sm">
        <div>
          <span class="font-medium text-gray-800">{{ p.name }}</span>
          <span class="ml-2 text-xs text-gray-400">
            window {{ p.alert_window_seconds }}s &bull; max {{ p.alert_max_requests }} req &bull; {{ p.alert_max_error_rate|floatformat:0 }}% err rate
          </span>
        </div>
        <div class="flex items-center gap-3">
          <form method="post" action="{% url 'nginxmon-test-telegram' p.pk %}" class="inline">
            {% csrf_token %}
            <button type="submit" class="text-xs text-blue-600 hover:underline">Test Telegram</button>
          </form>
          <a href="{% url 'nginxmon-profile-edit' p.pk %}" class="text-xs text-gray-500 hover:underline">Edit</a>
          <a href="{% url 'nginxmon-profile-delete' p.pk %}" class="text-xs text-red-400 hover:underline">Delete</a>
        </div>
      </div>
      {% endfor %}
    </div>
  </div>
  {% endif %}

  <!-- Threat alerts -->
  <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 gap-2">
      <i class="fas fa-exclamation-triangle text-yellow-500 text-sm"></i>
      <span class="text-sm font-semibold text-gray-700">Threat Alerts</span>
      {% if active_alerts %}<span class="ml-1 bg-red-100 text-red-700 text-xs font-medium px-1.5 py-0.5 rounded">{{ active_alerts }}</span>{% endif %}
    </div>
    <div id="alerts-container"
         hx-get="{% url 'nginxmon-alerts-partial' %}"
         hx-trigger="every 15s"
         hx-swap="innerHTML">
      {% include 'nginxmon/_alerts.html' %}
    </div>
  </div>

  <!-- Live log feed -->
  <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">
      <div class="flex items-center gap-2 text-sm font-semibold text-gray-700">
        <span class="w-2 h-2 rounded-full bg-green-400 animate-pulse inline-block"></span>
        Live Access Log
      </div>
      <span class="text-xs text-gray-400">Auto-refreshes every 5s &bull; last 60 entries</span>
    </div>
    <div class="overflow-x-auto">
      <table class="min-w-full text-xs">
        <thead class="bg-gray-50 border-b border-gray-100 select-none">
          <tr>
            <th data-sort="timestamp" onclick="setSort('timestamp')" class="px-3 py-2 text-left text-gray-500 font-semibold cursor-pointer hover:bg-gray-100 whitespace-nowrap">Time <span class="sort-icon text-gray-400 ml-0.5">▼</span></th>
            <th data-sort="ip"        onclick="setSort('ip')"        class="px-3 py-2 text-left text-gray-500 font-semibold cursor-pointer hover:bg-gray-100">IP <span class="sort-icon text-gray-300 ml-0.5">⇅</span></th>
            <th class="px-3 py-2 text-left text-gray-500 font-semibold hidden sm:table-cell">Location</th>
            <th data-sort="method"    onclick="setSort('method')"    class="px-3 py-2 text-left text-gray-500 font-semibold cursor-pointer hover:bg-gray-100">Method <span class="sort-icon text-gray-300 ml-0.5">⇅</span></th>
            <th class="px-3 py-2 text-left text-gray-500 font-semibold">Path</th>
            <th data-sort="service"   onclick="setSort('service')"   class="px-3 py-2 text-left text-gray-500 font-semibold cursor-pointer hover:bg-gray-100 hidden md:table-cell">Service <span class="sort-icon text-gray-300 ml-0.5">⇅</span></th>
            <th data-sort="status"    onclick="setSort('status')"    class="px-3 py-2 text-right text-gray-500 font-semibold cursor-pointer hover:bg-gray-100">Status <span class="sort-icon text-gray-300 ml-0.5">⇅</span></th>
            <th data-sort="time"      onclick="setSort('time')"      class="px-3 py-2 text-right text-gray-500 font-semibold cursor-pointer hover:bg-gray-100 hidden lg:table-cell">Time(s) <span class="sort-icon text-gray-300 ml-0.5">⇅</span></th>
            <th class="px-3 py-2 text-left text-gray-500 font-semibold hidden xl:table-cell">Note</th>
          </tr>
        </thead>
        <tbody id="live-log-body" class="divide-y divide-gray-50">
          {% include 'nginxmon/_live_logs.html' %}
        </tbody>
      </table>
    </div>
  </div>

  <!-- ── IP Ban Modal ──────────────────────────────────────────────────────── -->
  <div id="ip-ban-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4"
       onclick="if(event.target===this)this.classList.add('hidden')">
    <div class="absolute inset-0 bg-black/40"></div>
    <div class="relative bg-white rounded-xl shadow-2xl w-full max-w-lg">
      <div class="px-6 py-4 border-b border-gray-100 flex items-center justify-between">
        <div>
          <h2 class="text-sm font-semibold text-gray-900 flex items-center gap-2">
            <i class="fas fa-ban text-red-500"></i> Ban IP / CIDR
          </h2>
          <p class="text-xs text-gray-400 mt-0.5">
            Adds to <code class="bg-gray-100 px-1 rounded text-xs">block-cidrs-manual</code> ConfigMap.
            Separate multiple entries with commas or newlines.
          </p>
        </div>
        <button onclick="document.getElementById('ip-ban-modal').classList.add('hidden')"
                class="text-gray-400 hover:text-gray-600 text-lg leading-none ml-4">&times;</button>
      </div>
      <form method="post" action="{% url 'nginxmon-ip-ban' %}" class="p-6 space-y-4">
        {% csrf_token %}
        <textarea name="ips" rows="4" autofocus
                  placeholder="1.2.3.4&#10;5.6.7.0/24&#10;8.8.8.8, 9.9.9.9"
                  class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-red-400 focus:border-transparent resize-none"></textarea>
        <div class="flex items-center justify-between">
          <p class="text-xs text-gray-400">
            <i class="fas fa-info-circle mr-1"></i>Duplicates are skipped automatically.
          </p>
          <div class="flex gap-2">
            <button type="button"
                    onclick="document.getElementById('ip-ban-modal').classList.add('hidden')"
                    class="px-4 py-2 text-xs rounded-md bg-gray-100 text-gray-600 hover:bg-gray-200 font-medium">
              Cancel
            </button>
            <button type="submit"
                    class="inline-flex items-center px-5 py-2 bg-red-600 text-white text-xs font-medium rounded-md hover:bg-red-700 transition-colors">
              <i class="fas fa-ban mr-1.5"></i> Ban IPs
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>

  <!-- ── Banned IPs ─────────────────────────────────────────────────────── -->
  <div class="bg-white shadow-sm rounded-lg border border-gray-200 overflow-hidden">
    <div class="px-6 py-4 bg-red-50 border-b border-red-200 flex items-center justify-between">
      <div class="flex items-center gap-2">
        <i class="fas fa-ban text-red-500"></i>
        <h2 class="text-sm font-semibold text-red-800">Banned IPs</h2>
        <span class="ml-1 px-2 py-0.5 rounded-full bg-red-100 text-red-700 text-xs font-bold">{{ banned_ips|length }}</span>
      </div>
    </div>
    {% if banned_ips %}
    <div class="overflow-x-auto">
      <table class="min-w-full text-xs">
        <thead class="bg-gray-50 border-b border-gray-100">
          <tr>
            <th class="px-4 py-2 text-left text-gray-500 font-semibold">IP</th>
            <th class="px-4 py-2 text-left text-gray-500 font-semibold hidden sm:table-cell">Location</th>
            <th class="px-4 py-2 text-left text-gray-500 font-semibold">Source</th>
            <th class="px-4 py-2 text-left text-gray-500 font-semibold">Reason</th>
            <th class="px-4 py-2 text-right text-gray-500 font-semibold">Requests</th>
            <th class="px-4 py-2 text-left text-gray-500 font-semibold hidden md:table-cell">Banned At</th>
            <th class="px-4 py-2"></th>
          </tr>
        </thead>
        <tbody class="divide-y divide-gray-50">
          {% for ban in banned_ips %}
          <tr class="{% if ban.is_unbanned %}bg-green-50 hover:bg-green-100{% else %}hover:bg-gray-50{% endif %}">
            <td class="px-4 py-2 font-mono font-medium">
              <button class="hover:underline {% if ban.is_unbanned %}text-green-700 line-through{% else %}text-red-700{% endif %}"
                      onclick="setFilter('ip','{{ ban.ip }}')">{{ ban.ip }}</button>
            </td>
            <td class="px-4 py-2 hidden sm:table-cell {% if ban.is_unbanned %}text-green-600{% else %}text-gray-500{% endif %}">
              {% if ban.city or ban.country %}{{ ban.city }}{% if ban.city and ban.country %}, {% endif %}{{ ban.country }}{% else %}—{% endif %}
            </td>
            <td class="px-4 py-2">
              <span class="inline-block px-2 py-0.5 rounded text-xs font-semibold
                {% if ban.ban_source == 'manual' %}bg-gray-100 text-gray-700
                {% elif ban.ban_source == 'auto_auth_probe' %}bg-purple-100 text-purple-700
                {% elif ban.ban_source == 'auto_php_scan' %}bg-orange-100 text-orange-700
                {% else %}bg-yellow-100 text-yellow-700{% endif %}">
                {{ ban.get_ban_source_display }}
              </span>
            </td>
            <td class="px-4 py-2 max-w-sm truncate {% if ban.is_unbanned %}text-green-600{% else %}text-gray-600{% endif %}"
                title="{{ ban.reason }}"><span class="{% if ban.is_unbanned %}line-through{% endif %}">{{ ban.reason }}</span></td>
            <td class="px-4 py-2 text-right font-mono {% if ban.is_unbanned %}text-green-500{% else %}text-gray-500{% endif %}">{{ ban.request_count }}</td>
            <td class="px-4 py-2 hidden md:table-cell {% if ban.is_unbanned %}text-green-600{% else %}text-gray-400 whitespace-nowrap{% endif %}">
              <span class="{% if ban.is_unbanned %}line-through text-gray-400{% endif %}">{{ ban.banned_at|date:"m/d H:i" }}</span>
              {% if ban.is_unbanned %}
              <br><span class="text-green-700 font-medium">&#10003; unbanned {{ ban.unbanned_at|date:"m/d H:i" }}</span>
              {% endif %}
            </td>
            <td class="px-4 py-2 text-right">
              {% if ban.is_unbanned %}
              <span class="inline-flex items-center gap-1 px-2 py-0.5 rounded bg-green-100 text-green-700 text-xs font-semibold">
                <i class="fas fa-check"></i> Unbanned
              </span>
              {% else %}
              <form method="post" action="{% url 'nginxmon-unban' ban.pk %}" class="inline"
                    onsubmit="return confirm('Unban {{ ban.ip }}?')">
                {% csrf_token %}
                <button type="submit"
                        class="text-xs text-gray-400 hover:text-red-600 hover:underline">Unban</button>
              </form>
              {% endif %}
            </td>
          </tr>
          {% endfor %}
        </tbody>
      </table>
    </div>
    {% else %}
    <div class="px-6 py-8 text-center text-gray-400 text-sm">No IPs banned yet.</div>
    {% endif %}
  </div>

</div>

<script>
// ── Timeline chart ────────────────────────────────────────────────────────────
const timelineChart = echarts.init(document.getElementById('timelineChart'));
const _currentRange = '{{ current_range }}';

function loadTimeline() {
  fetch('{% url "nginxmon-chart-data" %}?range=' + _currentRange)
    .then(r => r.json())
    .then(data => {
      const titleEl = document.getElementById('chart-title');
      if (titleEl && data.label) titleEl.textContent = data.label;
      timelineChart.setOption({
        tooltip: { trigger: 'axis' },
        legend: { data: ['Total', 'Errors'], bottom: 0, textStyle: { fontSize: 11 } },
        grid: { top: 10, right: 10, bottom: 30, left: 40 },
        xAxis: { type: 'category', data: data.labels, axisLabel: { fontSize: 10, rotate: data.labels.length > 30 ? 30 : 0 } },
        yAxis: { type: 'value', axisLabel: { fontSize: 10 }, minInterval: 1 },
        series: [
          { name: 'Total', type: 'line', data: data.total, smooth: true,
            areaStyle: { opacity: 0.1 }, lineStyle: { color: '#6366f1' }, itemStyle: { color: '#6366f1' } },
          { name: 'Errors', type: 'line', data: data.errors, smooth: true,
            areaStyle: { opacity: 0.1 }, lineStyle: { color: '#ef4444' }, itemStyle: { color: '#ef4444' } },
        ],
      });
    });
}
loadTimeline();
setInterval(loadTimeline, 30000);
window.addEventListener('resize', () => timelineChart.resize());

// ── Status pie chart ──────────────────────────────────────────────────────────
const statusChart = echarts.init(document.getElementById('statusChart'));
const _statusColors = { '2': '#22c55e', '3': '#3b82f6', '4': '#f59e0b', '5': '#ef4444' };
statusChart.setOption({
  tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
  legend: { type: 'scroll', bottom: 0, textStyle: { fontSize: 10 } },
  series: [{
    type: 'pie', radius: ['35%', '65%'], center: ['50%', '45%'],
    data: {{ status_dist_json|safe }}.map(s => ({
      name: String(s.status), value: s.count,
      itemStyle: { color: _statusColors[String(s.status)[0]] || '#94a3b8' },
    })),
    label: { fontSize: 10 },
    cursor: 'pointer',
  }],
});
statusChart.on('click', p => setFilter('status', p.name));
window.addEventListener('resize', () => statusChart.resize());

// ── Top paths bar chart ───────────────────────────────────────────────────────
const _pathsData = {{ top_paths_json|safe }};
const pathsChart = echarts.init(document.getElementById('pathsChart'));
(function() {
  const rows = _pathsData.slice().reverse();  // bottom-to-top in ECharts yAxis
  const labels = rows.map(r => r.request_uri || '(empty)');
  const totals = rows.map(r => r.count - r.errors);
  const errors = rows.map(r => r.errors);
  pathsChart.setOption({
    tooltip: {
      trigger: 'axis', axisPointer: { type: 'shadow' },
      formatter: params => {
        const ok = params.find(p => p.seriesName === 'OK');
        const err = params.find(p => p.seriesName === 'Errors');
        const total = (ok ? ok.value : 0) + (err ? err.value : 0);
        return `<div style="max-width:300px;word-break:break-all">${params[0].name}</div>`
             + `<div>Total: <b>${total}</b>  Errors: <b style="color:#ef4444">${err ? err.value : 0}</b></div>`;
      },
    },
    grid: { left: 8, right: 24, top: 4, bottom: 4, containLabel: true },
    xAxis: { type: 'value', splitLine: { lineStyle: { color: '#f1f5f9' } },
             axisLabel: { fontSize: 10, color: '#94a3b8' } },
    yAxis: {
      type: 'category', data: labels,
      axisLabel: {
        fontSize: 10, color: '#475569', width: 260, overflow: 'truncate',
        formatter: v => v.length > 52 ? v.slice(0, 50) + '…' : v,
      },
    },
    series: [
      { name: 'OK', type: 'bar', stack: 'total', data: totals,
        itemStyle: { color: '#6366f1', borderRadius: [0,0,0,0] },
        emphasis: { itemStyle: { color: '#4f46e5' } } },
      { name: 'Errors', type: 'bar', stack: 'total', data: errors,
        itemStyle: { color: '#f87171', borderRadius: [0,2,2,0] },
        emphasis: { itemStyle: { color: '#ef4444' } } },
    ],
  });
  pathsChart.on('click', p => setFilter('path', p.name));
})();
window.addEventListener('resize', () => pathsChart.resize());
</script>

<script>
// ── Live-log filter & sort state ──────────────────────────────────────────────
const _logBase = '{% url "nginxmon-live-logs" %}';
const _f = { ip: '', status: '', service: '', path: '', sort: 'timestamp', order: 'desc' };

function _logsUrl() {
  const p = new URLSearchParams();
  if (_f.ip)      p.set('ip',      _f.ip);
  if (_f.status)  p.set('status',  _f.status);
  if (_f.service) p.set('service', _f.service);
  if (_f.path)    p.set('path',    _f.path);
  p.set('sort',  _f.sort);
  p.set('order', _f.order);
  return _logBase + '?' + p;
}

function _refreshLogs() {
  htmx.ajax('GET', _logsUrl(), {target: '#live-log-body', swap: 'innerHTML'});
  _renderChips();
  _updateSortIcons();
}

function setFilter(type, value) {
  _f[type] = (_f[type] === String(value)) ? '' : String(value);
  _refreshLogs();
}

function clearFilter(type) { _f[type] = ''; _refreshLogs(); }

function setSort(col) {
  if (_f.sort === col) { _f.order = _f.order === 'desc' ? 'asc' : 'desc'; }
  else                 { _f.sort = col; _f.order = 'desc'; }
  _refreshLogs();
}

function _renderChips() {
  const c = document.getElementById('active-filters');
  if (!c) return;
  const items = [['ip', _f.ip, 'IP'], ['status', _f.status, 'Status'], ['service', _f.service, 'Service'], ['path', _f.path, 'Path']].filter(([,v]) => v);
  c.innerHTML = items.map(([t, v]) =>
    `<span class="inline-flex items-center gap-1 px-2 py-0.5 bg-indigo-100 text-indigo-700 text-xs rounded-full font-medium">
       <span class="opacity-60 capitalize">${t}:</span><span class="font-mono">${v}</span>
       <button onclick="clearFilter('${t}')" class="text-indigo-400 hover:text-indigo-800 font-bold leading-none ml-0.5">&times;</button>
     </span>`
  ).join('');
}

function _updateSortIcons() {
  document.querySelectorAll('th[data-sort]').forEach(th => {
    const icon = th.querySelector('.sort-icon');
    if (!icon) return;
    if (_f.sort === th.dataset.sort) {
      icon.textContent = _f.order === 'asc' ? '▲' : '▼';
      icon.className = 'sort-icon text-indigo-500 ml-0.5';
    } else {
      icon.textContent = '⇅';
      icon.className = 'sort-icon text-gray-300 ml-0.5';
    }
  });
}

// Auto-poll live logs every 5s using JS interval (no HTMX trigger needed)
setInterval(_refreshLogs, 5000);
</script>

<script>
// ── Ingestion toggle ──────────────────────────────────────────────────────────
const _csrfToken = '{{ csrf_token }}';

function toggleIngestion() {
  fetch('{% url "nginxmon-toggle" %}', {
    method: 'POST',
    headers: { 'X-CSRFToken': _csrfToken },
  })
  .then(r => r.json())
  .then(d => _applyToggleUI(d.enabled))
  .catch(console.error);
}

function _applyToggleUI(enabled) {
  const base = 'inline-flex items-center px-3 py-1.5 text-xs rounded-md font-medium transition-colors';
  const btn  = document.getElementById('ingest-toggle');
  const dot  = document.getElementById('toggle-dot');
  const lbl  = document.getElementById('toggle-label');
  if (!btn) return;
  if (enabled) {
    btn.className = base + ' bg-green-100 text-green-700 hover:bg-green-200';
    dot.className = 'w-1.5 h-1.5 rounded-full mr-1.5 bg-green-500';
    lbl.textContent = 'Ingestion On';
  } else {
    btn.className = base + ' bg-gray-200 text-gray-500 hover:bg-gray-300';
    dot.className = 'w-1.5 h-1.5 rounded-full mr-1.5 bg-gray-400';
    lbl.textContent = 'Ingestion Off';
  }
}

// ── SSE status stream ─────────────────────────────────────────────────────────
(function startStatusStream() {
  const es = new EventSource('{% url "nginxmon-status-stream" %}');
  es.onmessage = function(e) {
    const d = JSON.parse(e.data);
    _applyToggleUI(d.enabled);

    const totalEl = document.getElementById('ingest-total');
    if (totalEl) totalEl.textContent = d.total_logs.toLocaleString() + ' logs';

    if (d.last_fetch_at) {
      const diff = Math.round((Date.now() - new Date(d.last_fetch_at)) / 1000);
      let rel;
      if (diff < 60)        rel = diff + 's ago';
      else if (diff < 3600) rel = Math.floor(diff / 60) + 'm ago';
      else                  rel = Math.floor(diff / 3600) + 'h ago';
      const lastEl = document.getElementById('ingest-last-fetch');
      if (lastEl) lastEl.textContent = 'Last: ' + rel;
    }
  };
  es.onerror = function() { es.close(); setTimeout(startStatusStream, 5000); };
})();
</script>

<script>
// ── Geo map ───────────────────────────────────────────────────────────────────
(function() {
  // ISO alpha-2 → ISO numeric  (needed to join with world-atlas features)
  const _a2n = {
    AF:4,AL:8,DZ:12,AS:16,AD:20,AO:24,AG:28,AR:32,AM:51,AW:533,AU:36,AT:40,
    AZ:31,BS:44,BH:48,BD:50,BB:52,BY:112,BE:56,BZ:84,BJ:204,BT:64,BO:68,
    BA:70,BW:72,BR:76,BN:96,BG:100,BF:854,BI:108,KH:116,CM:120,CA:124,CV:132,
    CF:140,TD:148,CL:152,CN:156,CO:170,KM:174,CG:178,CD:180,CR:188,CI:384,
    HR:191,CU:192,CY:196,CZ:203,DK:208,DJ:262,DM:212,DO:214,EC:218,EG:818,
    SV:222,GQ:226,ER:232,EE:233,ET:231,FJ:242,FI:246,FR:250,GA:266,GM:270,
    GE:268,DE:276,GH:288,GR:300,GL:304,GD:308,GT:320,GN:324,GW:624,GY:328,
    HT:332,HN:340,HK:344,HU:348,IS:352,IN:356,ID:360,IR:364,IQ:368,IE:372,
    IL:376,IT:380,JM:388,JP:392,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,MK:807,MG:450,MW:454,MY:458,MV:462,ML:466,MT:470,MH:584,
    MR:478,MU:480,MX:484,FM:583,MD:498,MC:492,MN:496,ME:499,MA:504,MZ:508,
    MM:104,NA:516,NR:520,NP:524,NL:528,NC:540,NZ:554,NI:558,NE:562,NG:566,
    NO:578,OM:512,PK:586,PW:585,PS:275,PA:591,PG:598,PY:600,PE:604,PH:608,
    PL:616,PT:620,PR:630,QA:634,RO:642,RU:643,RW:646,KN:659,LC:662,VC:670,
    WS:882,SM:674,ST:678,SA:682,SN:686,RS:688,SC:690,SL:694,SG:702,SK:703,
    SI:705,SB:90,SO:706,ZA:710,ES:724,LK:144,SD:736,SR:740,SZ:748,SE:752,
    CH:756,SY:760,TW:158,TJ:762,TZ:834,TH:764,TL:626,TG:768,TO:776,TT:780,
    TN:788,TR:792,TM:795,TV:798,UG:800,UA:804,AE:784,GB:826,US:840,UY:858,
    UZ:860,VU:548,VE:862,VN:704,YE:887,ZM:894,ZW:716
  };

  const container = document.getElementById('geoMap');
  if (!container) return;

  const h = 340;
  let w = container.clientWidth || 800;

  const svg = d3.select('#geoMap').append('svg')
    .attr('width', w).attr('height', h)
    .style('background', '#f8fafc').style('border-radius', '4px');

  const tooltip = d3.select('body').append('div')
    .style('position', 'fixed').style('display', 'none').style('pointer-events', 'none')
    .style('z-index', '9999').style('max-width', '200px')
    .attr('class', 'bg-gray-900 text-white text-xs rounded px-2 py-1.5 shadow-lg');

  const g = svg.append('g');

  function makeProjection(width) {
    return d3.geoNaturalEarth1()
      .scale(width / 6.3)
      .translate([width / 2, h / 2]);
  }
  let projection = makeProjection(w);
  let pathGen = d3.geoPath(projection);

  svg.call(d3.zoom().scaleExtent([1, 8])
    .on('zoom', e => g.attr('transform', e.transform)));

  const colorScale = d3.scaleSequentialLog(d3.interpolateBlues);
  let cachedWorld = null, cachedGeo = null;

  function render(world, geoData) {
    cachedWorld = world; cachedGeo = geoData;
    const features = topojson.feature(world, world.objects.countries).features;

    const byNum = {};
    geoData.countries.forEach(c => {
      const n = _a2n[c.country_code];
      if (n) byNum[n] = c;
    });
    const maxTotal = Math.max(1, ...geoData.countries.map(c => c.total));
    colorScale.domain([1, maxTotal]);

    // Countries
    g.selectAll('.country').data(features).join('path')
      .attr('class', 'country')
      .attr('d', pathGen)
      .attr('fill', d => { const cd = byNum[+d.id]; return cd ? colorScale(cd.total) : '#e5e7eb'; })
      .attr('stroke', '#fff').attr('stroke-width', 0.4)
      .on('mouseover', function(e, d) {
        const cd = byNum[+d.id];
        if (!cd) return;
        d3.select(this).attr('stroke', '#6366f1').attr('stroke-width', 1.2);
        tooltip.style('display', 'block')
          .html(`<div class="font-semibold">${cd.country}</div>
                 <div>${cd.total.toLocaleString()} requests</div>
                 <div class="text-red-300">${cd.errors.toLocaleString()} errors</div>`);
      })
      .on('mousemove', e => {
        tooltip.style('left', Math.min(e.clientX + 12, window.innerWidth - 180) + 'px')
               .style('top', (e.clientY - 40) + 'px');
      })
      .on('mouseout', function() {
        d3.select(this).attr('stroke', '#fff').attr('stroke-width', 0.4);
        tooltip.style('display', 'none');
      });

    // Graticule
    g.selectAll('.graticule').data([d3.geoGraticule()()]).join('path')
      .attr('class', 'graticule').attr('d', pathGen)
      .attr('fill', 'none').attr('stroke', '#e2e8f0').attr('stroke-width', 0.3);

    // Bubbles
    const maxBubble = Math.max(1, ...geoData.bubbles.map(b => b.total));
    const rScale = d3.scaleSqrt().domain([1, maxBubble]).range([2, 18]);

    g.selectAll('.bubble').data(geoData.bubbles).join('circle')
      .attr('class', 'bubble')
      .attr('cx', d => { const p = projection([d.lon, d.lat]); return p ? p[0] : -999; })
      .attr('cy', d => { const p = projection([d.lon, d.lat]); return p ? p[1] : -999; })
      .attr('r', d => rScale(d.total))
      .attr('fill', d => d.errors > 0 ? 'rgba(239,68,68,0.45)' : 'rgba(99,102,241,0.45)')
      .attr('stroke', d => d.errors > 0 ? '#ef4444' : '#6366f1')
      .attr('stroke-width', 0.6)
      .on('mouseover', function(e, d) {
        d3.select(this).attr('stroke-width', 1.5);
        tooltip.style('display', 'block')
          .html(`<div class="font-semibold">${d.label}</div>
                 <div>${d.total.toLocaleString()} requests</div>
                 <div class="text-red-300">${d.errors.toLocaleString()} errors</div>`);
      })
      .on('mousemove', e => {
        tooltip.style('left', Math.min(e.clientX + 12, window.innerWidth - 180) + 'px')
               .style('top', (e.clientY - 40) + 'px');
      })
      .on('mouseout', function() {
        d3.select(this).attr('stroke-width', 0.6);
        tooltip.style('display', 'none');
      });

    // Legend
    const legendEl = document.getElementById('geo-legend');
    if (legendEl) {
      legendEl.innerHTML =
        `<span class="flex items-center gap-1"><span class="w-3 h-3 rounded-sm inline-block" style="background:#dbeafe;border:1px solid #93c5fd"></span>Low</span>` +
        `<span class="flex items-center gap-1"><span class="w-3 h-3 rounded-sm inline-block" style="background:#1d4ed8"></span>High</span>` +
        `<span class="ml-1 flex items-center gap-1"><span class="w-3 h-3 rounded-full inline-block" style="background:rgba(99,102,241,0.45);border:1px solid #6366f1"></span>Requests</span>` +
        `<span class="flex items-center gap-1"><span class="w-3 h-3 rounded-full inline-block" style="background:rgba(239,68,68,0.45);border:1px solid #ef4444"></span>w/ Errors</span>`;
    }
  }

  // Load world + geo data
  Promise.all([
    d3.json('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json'),
    fetch('{% url "nginxmon-geo-stats" %}?range={{ current_range }}').then(r => r.json()),
  ]).then(([world, geoData]) => render(world, geoData))
    .catch(err => console.warn('Geo map load failed:', err));

  // Resize
  window.addEventListener('resize', () => {
    w = container.clientWidth;
    svg.attr('width', w);
    projection = makeProjection(w);
    pathGen = d3.geoPath(projection);
    if (cachedWorld && cachedGeo) render(cachedWorld, cachedGeo);
  });
})();
</script>
{% endblock %}
