{% extends "base.html" %}

{% block css %}
.container {
    max-width: 900px;
    margin: 0 auto;
    padding: 10px;
}
#pause-button {
    white-space: nowrap;
    padding: 4px 10px;
    font-size: 0.9rem;
    border-radius: 6px;
}

.packet-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
    color: #e4e9ee;
}
.packet-table th, .packet-table td {
    border: 1px solid #3a3f44;
    padding: 6px 10px;
    text-align: left;
}
.packet-table th {
    background-color: #1f2226;
    font-weight: bold;
}
.packet-table tr:nth-of-type(odd) { background-color: #272b2f; }
.packet-table tr:nth-of-type(even) { background-color: #212529; }
.port-tag {
    display: inline-block;
    padding: 1px 6px;
    border-radius: 6px;
    font-size: 0.75rem;
    font-weight: 500;
    color: #fff;
}

/* --- Color-coded port labels --- */
.port-0  { background-color: #6c757d; }
.port-1  { background-color: #007bff; }
.port-3  { background-color: #28a745; }
.port-4  { background-color: #ffc107; }
.port-5  { background-color: #dc3545; }
.port-6  { background-color: #20c997; }
.port-65 { background-color: #ff66b3; }
.port-67 { background-color: #17a2b8; }
.port-70 { background-color: #6f42c1; }
.port-71 { background-color: #fd7e14; }

.to-mqtt {
    font-style: italic;
    color: #aaa;
}

/* --- Payload rows --- */
.payload-row {
    display: none;
    background-color: #1b1e22;
}
.payload-cell {
    padding: 8px 12px;
    font-family: monospace;
    white-space: pre-wrap;
    color: #b0bec5;
    border-top: none;
}
.packet-table tr.expanded + .payload-row {
    display: table-row;
}
.toggle-btn {
    cursor: pointer;
    color: #aaa;
    margin-right: 6px;
    font-weight: bold;
}
.toggle-btn:hover {
    color: #fff;
}
{% endblock %}

{% block body %}
<div class="container">
    <form class="d-flex align-items-center justify-content-between mb-3">
        <h5 class="mb-0">📡 Live Feed</h5>
        <button type="button" id="pause-button" class="btn btn-sm btn-outline-secondary">Pause</button>
    </form>

    <table class="packet-table">
        <thead>
            <tr>
                <th>Packet ID</th>
                <th>From</th>
                <th>To</th>
                <th>Port</th>
                <th>Links</th>
            </tr>
        </thead>
        <tbody id="packet_list"></tbody>
    </table>
</div>

<script>
let lastImportTime = null;
let updatesPaused = false;
let nodeMap = {};
let updateInterval = 3000;

const PORT_MAP = {
    0: "UNKNOWN APP",
    1: "Text Message",
    3: "Position",
    4: "Node Info",
    5: "Routing",
    6: "Administration",
    8: "Waypoint",
    65: "Store Forward",
    67: "Telemetry",
    70: "Trace Route",
    71: "Neighbor Info",
};

const PORT_COLORS = {
    0: "#6c757d",
    1: "#007bff",
    3: "#28a745",
    4: "#ffc107",
    5: "#dc3545",
    6: "#20c997",
    65: "#6610f2",
    67: "#17a2b8",
    68: "#fd7e14",
    69: "#6f42c1",
    70: "#ff4444",
    71: "#ff66cc",
    72: "#00cc99",
    73: "#9999ff",
    74: "#cc00cc",
    75: "#ffbb33",
    76: "#00bcd4",
    77: "#8bc34a",
    78: "#795548"
};

// --- Load node names ---
async function loadNodes() {
    const res = await fetch("/api/nodes");
    if (!res.ok) return;
    const data = await res.json();
    for (const n of data.nodes || []) {
        const name = n.long_name || n.short_name || n.id || n.node_id;
        nodeMap[n.node_id] = name;
    }
    nodeMap[4294967295] = "All";
}

function nodeName(id) {
    if (id === 4294967295) return `<span class="to-mqtt">All</span>`;
    return nodeMap[id] || id;
}

function portLabel(portnum, payload) {
    const name = PORT_MAP[portnum] || "Unknown";
    const color = PORT_COLORS[portnum] || "#6c757d";
    const safePayload = payload ? payload.replace(/"/g, "&quot;") : "";
    return `<span class="port-tag" style="background-color:${color}" title="${safePayload}">${name}</span>
            <span class="text-secondary">(${portnum})</span>`;
}

// --- Fetch firehose interval from shared site config ---
async function configureFirehose() {
    try {
        const cfg = await window._siteConfigPromise;
        const intervalSec = cfg?.site?.firehose_interval;
        if (intervalSec && !isNaN(intervalSec)) {
            updateInterval = parseInt(intervalSec) * 1000;
        }
        console.log("Firehose update interval:", updateInterval, "ms");
    } catch (err) {
        console.warn("Failed to read firehose interval:", err);
    }
}

// --- Fetch and render packets ---
async function fetchUpdates() {
    if (updatesPaused) return;
    const url = new URL("/api/packets", window.location.origin);
    if (lastImportTime) url.searchParams.set("since", lastImportTime);
    url.searchParams.set("limit", 50);

    try {
        const res = await fetch(url);
        if (!res.ok) return;
        const data = await res.json();
        const packets = data.packets || [];
        if (!packets.length) return;

        const list = document.getElementById("packet_list");

        for (const pkt of packets.reverse()) {
            const fromNodeId = pkt.from_node_id;
            const toNodeId = pkt.to_node_id;

            let from = fromNodeId === 4294967295 ? `<span class="to-mqtt">All</span>` :
                       `<a href="/packet_list/${fromNodeId}" style="text-decoration:underline; color:inherit;">${nodeMap[fromNodeId] || fromNodeId}</a>`;

            let to = toNodeId === 1 ? `<span class="to-mqtt">direct to MQTT</span>` :
                     toNodeId === 4294967295 ? `<span class="to-mqtt">All</span>` :
                     `<a href="/packet_list/${toNodeId}" style="text-decoration:underline; color:inherit;">${nodeMap[toNodeId] || toNodeId}</a>`;

            let links = "";
            if (pkt.portnum === 3 && pkt.payload) {
                const latMatch = pkt.payload.match(/latitude_i:\s*(-?\d+)/);
                const lonMatch = pkt.payload.match(/longitude_i:\s*(-?\d+)/);
                if (latMatch && lonMatch) {
                    const lat = parseInt(latMatch[1]) / 1e7;
                    const lon = parseInt(lonMatch[1]) / 1e7;
                    links += `<a href="https://www.google.com/maps?q=${lat},${lon}" target="_blank" rel="noopener noreferrer" style="font-weight:bold; text-decoration:none;">Map</a>`;
                }
            }

            if (pkt.portnum === 70) {
                let traceId = pkt.id;
                const idMatch = pkt.payload.match(/ID:\s*(\d+)/i);
                if (idMatch) traceId = idMatch[1];
                if (links) links += "&nbsp;|&nbsp;";
                links += `<a href="/graph/traceroute/${traceId}" target="_blank" rel="noopener noreferrer" style="font-weight:bold; text-decoration:none;">Graph</a>`;
            }

            const safePayload = (pkt.payload || "").replace(/</g, "&lt;").replace(/>/g, "&gt;");
            const html = `
<tr class="packet-row" data-id="${pkt.id}">
    <td><span class="toggle-btn">▶</span> <a href="/packet/${pkt.id}" style="text-decoration:underline; color:inherit;">${pkt.id}</a></td>
    <td>${from}</td>
    <td>${to}</td>
    <td>${portLabel(pkt.portnum, pkt.payload)}</td>
    <td>${links}</td>
</tr>
<tr class="payload-row">
    <td colspan="5" class="payload-cell">${safePayload}</td>
</tr>`;
            list.insertAdjacentHTML("afterbegin", html);
        }

        while (list.rows.length > 400) list.deleteRow(-1);
        lastImportTime = packets[packets.length - 1].import_time;

    } catch (err) {
        console.error("Packet fetch failed:", err);
    }
}

// --- Initialize ---
document.addEventListener("DOMContentLoaded", async () => {
    const pauseBtn = document.getElementById("pause-button");
    pauseBtn.addEventListener("click", () => {
        updatesPaused = !updatesPaused;
        pauseBtn.textContent = updatesPaused ? "Resume" : "Pause";
    });

    document.addEventListener("click", (e) => {
        const btn = e.target.closest(".toggle-btn");
        if (!btn) return;
        const row = btn.closest(".packet-row");
        row.classList.toggle("expanded");
        btn.textContent = row.classList.contains("expanded") ? "▼" : "▶";
    });

    await configureFirehose();
    await loadNodes();
    fetchUpdates();
    setInterval(fetchUpdates, updateInterval);
});
</script>

{% endblock %}