{% extends "base.html" %}

{% block css %}
table {
    width: 80%;
    border-collapse: collapse;
    margin: 1em auto;
}

th, td {
    padding: 10px;
    border: 1px solid #333;
    text-align: left;
}

th {
    background-color: #1f1f1f;
    color: white;
    position: sticky;
    top: 0;
    z-index: 2;
    cursor: pointer;
}

.sort-icon {
    font-size: 0.7em;
    margin-left: 4px;
}

tr:nth-child(even) {
    background-color: #181818;
}

tr:nth-child(odd) {
    background-color: #222;
}

tr:hover {
    background-color: #2a2a2a;
}

.filter-container {
    width: 80%;
    margin: 1em auto;
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

select, .export-btn, .search-box, .clear-btn {
    padding: 6px;
    border-radius: 4px;
    border: 1px solid #333;
    cursor: pointer;
}

.search-box {
    flex: 1;
}

.export-btn {
    background-color: #28a745;
    color: white;
    border: none;
}

.export-btn:hover {
    background-color: #218838;
}

.clear-btn {
    background-color: #dc3545;
    color: white;
    border: none;
}

.clear-btn:hover {
    background-color: #c82333;
}

.count-container {
    width: 80%;
    margin: 0 auto 10px;
    font-weight: bold;
    color: white;
}

.favorite-star {
    cursor: pointer;
    font-size: 1.2em;
    user-select: none;
    transition: color 0.2s;
}

.favorite-star:hover {
    transform: scale(1.2);
}

.favorite-star.active {
    color: #ffd700;
}

.favorites-btn {
    background-color: #ffd700;
    color: #000;
    border: none;
}

.favorites-btn:hover {
    background-color: #ffed4e;
}

.favorites-btn.active {
    background-color: #ff6b6b;
    color: white;
}
{% endblock %}

{% block body %}
<div class="filter-container">
    <input type="text" id="search-box" class="search-box" placeholder="Search by name or ID..." />

    <select id="role-filter">
        <option value="">All Roles</option>
    </select>

    <select id="channel-filter">
        <option value="">All Channels</option>
    </select>

    <select id="hw-filter">
        <option value="">All HW Models</option>
    </select>

    <select id="firmware-filter">
        <option value="">All Firmware</option>
    </select>

    <button class="favorites-btn" id="favorites-btn">⭐ Show Favorites</button>
    <button class="export-btn" id="export-btn">Export CSV</button>
    <button class="clear-btn" id="clear-btn">Clear Filters</button>
</div>

<div class="count-container">
    Showing <span id="node-count">0</span> nodes
</div>

<div id="node-list">
    <table>
        <thead>
            <tr>
                <th>Short<span class="sort-icon">▲</span></th>
                <th>Long Name <span class="sort-icon"></span></th>
                <th>HW Model <span class="sort-icon"></span></th>
                <th>Firmware <span class="sort-icon"></span></th>
                <th>Role <span class="sort-icon"></span></th>
                <th>Last Latitude <span class="sort-icon"></span></th>
                <th>Last Longitude <span class="sort-icon"></span></th>
                <th>Channel <span class="sort-icon"></span></th>
                <th>Last Update <span class="sort-icon"></span></th>
                <th>Favorite</th>
            </tr>
        </thead>
        <tbody id="node-table-body">
            <tr><td colspan="9" style="text-align:center; color:white;">Loading nodes...</td></tr>
        </tbody>
    </table>
</div>

<script>
let allNodes = [];
let sortColumn = "short_name"; // default sorted column
let sortAsc = true; // default ascending
let showOnlyFavorites = false;

// Declare headers and keyMap BEFORE any function that uses them
const headers = document.querySelectorAll("thead th");
const keyMap = ["short_name","long_name","hw_model","firmware","role","last_lat","last_long","channel","last_update"];

// LocalStorage functions for favorites
function getFavorites() {
    const favorites = localStorage.getItem('nodelist_favorites');
    return favorites ? JSON.parse(favorites) : [];
}

function saveFavorites(favorites) {
    localStorage.setItem('nodelist_favorites', JSON.stringify(favorites));
}

function toggleFavorite(nodeId) {
    let favorites = getFavorites();
    const index = favorites.indexOf(nodeId);
    if (index > -1) {
        favorites.splice(index, 1);
    } else {
        favorites.push(nodeId);
    }
    saveFavorites(favorites);
    applyFilters();
}

function isFavorite(nodeId) {
    return getFavorites().includes(nodeId);
}

document.addEventListener("DOMContentLoaded", async function() {
    const tbody = document.getElementById("node-table-body");
    const roleFilter = document.getElementById("role-filter");
    const channelFilter = document.getElementById("channel-filter");
    const hwFilter = document.getElementById("hw-filter");
    const firmwareFilter = document.getElementById("firmware-filter");
    const searchBox = document.getElementById("search-box");
    const countSpan = document.getElementById("node-count");
    const exportBtn = document.getElementById("export-btn");
    const clearBtn = document.getElementById("clear-btn");
    const favoritesBtn = document.getElementById("favorites-btn");

    try {
        const response = await fetch("/api/nodes?days_active=3");
        if (!response.ok) throw new Error("Failed to fetch nodes");
        const data = await response.json();
        allNodes = data.nodes;
        populateFilters(allNodes);
        renderTable(allNodes);
        updateSortIcons();
    } catch (err) {
        tbody.innerHTML = `<tr><td colspan="9" style="text-align:center; color:red;">Error loading nodes: ${err.message}</td></tr>`;
    }

    roleFilter.addEventListener("change", applyFilters);
    channelFilter.addEventListener("change", applyFilters);
    hwFilter.addEventListener("change", applyFilters);
    firmwareFilter.addEventListener("change", applyFilters);
    searchBox.addEventListener("input", applyFilters);
    exportBtn.addEventListener("click", exportToCSV);
    clearBtn.addEventListener("click", clearFilters);
    favoritesBtn.addEventListener("click", toggleFavoritesFilter);
    
    // Use event delegation for star clicks
    tbody.addEventListener("click", (e) => {
        if (e.target.classList.contains('favorite-star')) {
            const nodeId = parseInt(e.target.getAttribute('data-node-id'));
            
            // Get current favorites
            let favorites = getFavorites();
            const index = favorites.indexOf(nodeId);
            const isNowFavorite = index === -1; // Will it be a favorite after toggle?
            
            // Update the star immediately for instant feedback
            if (isNowFavorite) {
                e.target.classList.add('active');
                e.target.textContent = '★';
            } else {
                e.target.classList.remove('active');
                e.target.textContent = '☆';
            }
            
            // Save to localStorage
            toggleFavorite(nodeId);
        }
    });

    headers.forEach((th, index) => {
        th.addEventListener("click", () => {
            const key = keyMap[index];
            sortAsc = (sortColumn === key) ? !sortAsc : true;
            sortColumn = key;
            applyFilters(); // apply filters and sort
        });
    });

    function populateFilters(nodes) {
        const roles = new Set();
        const channels = new Set();
        const hws = new Set();
        const firmwares = new Set();

        nodes.forEach(n => {
            if (n.role) roles.add(n.role);
            if (n.channel) channels.add(n.channel);
            if (n.hw_model) hws.add(n.hw_model);
            if (n.firmware) firmwares.add(n.firmware);
        });

        fillSelect(roleFilter, roles);
        fillSelect(channelFilter, channels);
        fillSelect(hwFilter, hws);
        fillSelect(firmwareFilter, firmwares);
    }

    function fillSelect(select, values) {
        [...values].sort().forEach(v => {
            const option = document.createElement("option");
            option.value = v;
            option.textContent = v;
            select.appendChild(option);
        });
    }

    function toggleFavoritesFilter() {
        showOnlyFavorites = !showOnlyFavorites;
        if (showOnlyFavorites) {
            favoritesBtn.textContent = "⭐ Show All";
            favoritesBtn.classList.add("active");
        } else {
            favoritesBtn.textContent = "⭐ Show Favorites";
            favoritesBtn.classList.remove("active");
        }
        applyFilters();
    }

    function applyFilters() {
        const searchTerm = searchBox.value.trim().toLowerCase();

        let filtered = allNodes.filter(node => {
            const roleMatch = !roleFilter.value || node.role === roleFilter.value;
            const channelMatch = !channelFilter.value || node.channel === channelFilter.value;
            const hwMatch = !hwFilter.value || node.hw_model === hwFilter.value;
            const firmwareMatch = !firmwareFilter.value || node.firmware === firmwareFilter.value;

            const searchMatch = !searchTerm ||
                (node.long_name && node.long_name.toLowerCase().includes(searchTerm)) ||
                (node.short_name && node.short_name.toLowerCase().includes(searchTerm)) ||
                (node.node_id && node.node_id.toString().includes(searchTerm)) ||
                (node.id && node.id.toString().includes(searchTerm));

            const favoriteMatch = !showOnlyFavorites || isFavorite(node.node_id);

            return roleMatch && channelMatch && hwMatch && firmwareMatch && searchMatch && favoriteMatch;
        });

        if (sortColumn) {
            filtered = sortNodes(filtered, sortColumn, sortAsc);
        }

        renderTable(filtered);
        updateSortIcons();
    }

    function renderTable(nodes) {
        tbody.innerHTML = "";
        if (!nodes.length) {
            tbody.innerHTML = '<tr><td colspan="10" style="text-align:center; color:white;">No nodes found</td></tr>';
        } else {
            nodes.forEach(node => {
                const row = document.createElement("tr");
                const isFav = isFavorite(node.node_id);
                const starClass = isFav ? 'favorite-star active' : 'favorite-star';
                const starIcon = isFav ? '★' : '☆';
                
                row.innerHTML = `
                    <td>${node.short_name || "N/A"}</td>
                    <td><a href="/packet_list/${node.node_id}">${node.long_name || "N/A"}</a></td>
                    <td>${node.hw_model || "N/A"}</td>
                    <td>${node.firmware || "N/A"}</td>
                    <td>${node.role || "N/A"}</td>
                    <td>${node.last_lat ? (node.last_lat / 1e7).toFixed(7) : "N/A"}</td>
                    <td>${node.last_long ? (node.last_long / 1e7).toFixed(7) : "N/A"}</td>
                    <td>${node.channel || "N/A"}</td>
                    <td>${node.last_update ? new Date(node.last_update).toLocaleString() : "N/A"}</td>
                    <td style="text-align:center;"><span class="${starClass}" data-node-id="${node.node_id}">${starIcon}</span></td>
                `;
                
                tbody.appendChild(row);
            });
        }
        countSpan.textContent = nodes.length;
    }

    function clearFilters() {
        roleFilter.value = "";
        channelFilter.value = "";
        hwFilter.value = "";
        firmwareFilter.value = "";
        searchBox.value = "";
        sortColumn = "short_name";
        sortAsc = true;
        showOnlyFavorites = false;
        favoritesBtn.textContent = "⭐ Show Favorites";
        favoritesBtn.classList.remove("active");
        renderTable(allNodes);
        updateSortIcons();
    }

    function exportToCSV() {
        const rows = [];
        const headersText = Array.from(headers).map(th => `"${th.innerText.replace(/▲|▼/g,'')}"`);
        rows.push(headersText.join(","));

        const visibleRows = tbody.querySelectorAll("tr");
        visibleRows.forEach(tr => {
            if (tr.children.length === 9) {
                const row = Array.from(tr.children).map(td => `"${td.innerText.replace(/"/g, '""')}"`);
                rows.push(row.join(","));
            }
        });

        const csvContent = "data:text/csv;charset=utf-8,\uFEFF" + rows.join("\n");
        const link = document.createElement("a");
        link.href = encodeURI(csvContent);
        const dateStr = new Date().toISOString().slice(0,10);
        link.download = `nodes_list_${dateStr}.csv`;
        link.click();
    }

    function sortNodes(nodes, key, asc) {
        return [...nodes].sort((a, b) => {
            let valA = a[key] || "";
            let valB = b[key] || "";

            if (key === "last_lat" || key === "last_long") {
                valA = Number(valA) || 0;
                valB = Number(valB) || 0;
            }
            if (key === "last_update") {
                valA = valA ? new Date(valA).getTime() : 0;
                valB = valB ? new Date(valB).getTime() : 0;
            }

            if (valA < valB) return asc ? -1 : 1;
            if (valA > valB) return asc ? 1 : -1;
            return 0;
        });
    }

    function updateSortIcons() {
        headers.forEach((th, index) => {
            const span = th.querySelector(".sort-icon");
            if (!span) return;
            span.textContent = (keyMap[index] === sortColumn) ? (sortAsc ? "▲" : "▼") : "";
        });
    }
});
</script>
{% endblock %}
