<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OnTheSpot - Download Queue</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
    <script src="{{ url_for('static', filename='utils.js') }}" defer></script>
</head>
<body>
    <div class="header">
        <ul>
            <li class="hide-on-mobile"><a href="https://github.com/justin025/onthespot/" target="_blank">OnTheSpot</a></li>
            <li><a href="/search">Search</a></li>
            <li><a class="active" href="/download_queue">Downloads</a></li>
            <li><a href="/settings">Settings</a></li>
            <li><a href="/about">About</a></li>
        </ul>
    </div>

    <br>
    <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 15px;">
        <div style="display: flex; align-items: center;">
            <p id="queue-status-message" style="margin-right: 10px;">Total Items: 0 | Progress: 0%</p>
        </div>

        <div style="display: flex; align-items: center;">
            <button onclick="clearItems()" class="hide-on-mobile">Clear Completed/Cancelled</button>
            <button onclick="cancelItems()" class="hide-on-mobile">Cancel All</button>
            <button onclick="retryItems()" class="hide-on-mobile">Retry Cancelled/Failed</button>
            <button class="hide-on-mobile" onclick="restartWorkers()" style="margin-left: 10px;">Restart Workers</button>
            <button class="download-action-button"  onclick="toggleVisibility()" class="hide-on-mobile">
                <img id="collapse_button_icon" src="/icons/collapse_down.png" loading="lazy" style="width: 20px; height: 20px;">
            </button>
        </div>
    </div>

    <div id="toggle_visibility" style="display: none;  margin-top: 20px; margin-bottom: 15px;">
        <hr style="border: 1px solid #fff; margin-bottom: 20px;">
        <div style="display: flex; align-items: center; justify-content: space-between;">
            <div style="display: flex; align-items: center;">
                <label for="download_queue_show_waiting" style="margin-right: 5px; margin-left: 15px;">Show Waiting:</label>
                <input type="checkbox" id="download_queue_show_waiting" {% if config.download_queue_show_waiting %}checked{% endif %}>
                <label for="download_queue_show_failed" style="margin-right: 5px; margin-left: 15px;">Show Failed:</label>
                <input type="checkbox" id="download_queue_show_failed" {% if config.download_queue_show_failed %}checked{% endif %}>
                <label for="download_queue_show_cancelled" style="margin-right: 5px; margin-left: 15px;">Show Cancelled:</label>
                <input type="checkbox" id="download_queue_show_cancelled" {% if config.download_queue_show_cancelled %}checked{% endif %}>
                <label for="download_queue_show_unavailable" style="margin-right: 5px; margin-left: 15px;">Show Unavailable:</label>
                <input type="checkbox" id="download_queue_show_unavailable" {% if config.download_queue_show_unavailable %}checked{% endif %}>
                <label for="download_queue_show_completed" style="margin-right: 5px; margin-left: 15px;">Show Completed:</label>
                <input type="checkbox" id="download_queue_show_completed" {% if config.download_queue_show_completed %}checked{% endif %}>
            </div>
            <div style="display: flex; align-items: center;">
                <button class="download-action-button"  onclick="updateSettings(returnFilterData())" class="hide-on-mobile">
                    <img src="/icons/save.png" loading="lazy" style="width: 20px; height: 20px;">
                </button>
            </div>
        </div>
    </div>

    <table>
        <thead>
            <tr>
                <th style="display: none;">Local ID</th>
                {% if config.show_download_thumbnails %}
                    <th id="th-image">Image</th>
                {% endif %}
                <th id="th-name" onclick="setSort('item_name')" style="cursor:pointer; min-width: 12ch;">
                    Name
                    <span id="sort-indicator-item_name" class="sort-indicator"></span>
                </th>
                <th class="hide-on-mobile" id="th-by" onclick="setSort('parent_category')" style="cursor:pointer; min-width: 8ch;">
                    By
                    <span id="sort-indicator-parent_category" class="sort-indicator"></span>
                </th>
                <th id="th-service" onclick="setSort('item_service')" style="cursor:pointer; min-width: 8ch;">
                    Service
                    <span id="sort-indicator-item_service" class="sort-indicator"></span>
                </th>
                <th id="th-status" onclick="setSort('item_status')" style="cursor:pointer; min-width: 16ch;">
                    Status
                    <span id="sort-indicator-item_status" class="sort-indicator"></span>
                </th>
                <th class="hide-on-mobile" id="th-progress" onclick="setSort('progress')" style="cursor:pointer; min-width: 12em;">
                    Progress
                     <span id="sort-indicator-progress" class="sort-indicator"></span>
                </th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody id="download-queue-table">
            <!-- Items will be added here dynamically -->
        </tbody>
    </table>

    <script>
        const config = {{ config | tojson | safe }};
        function returnFilterData() {
            const filterData = {
                download_queue_show_waiting: document.getElementById('download_queue_show_waiting').checked,
                download_queue_show_completed: document.getElementById('download_queue_show_completed').checked,
                download_queue_show_cancelled: document.getElementById('download_queue_show_cancelled').checked,
                download_queue_show_failed: document.getElementById('download_queue_show_failed').checked,
                download_queue_show_unavailable: document.getElementById('download_queue_show_unavailable').checked,
            }
            return filterData
        }


        function fetchItems() {
            fetch('/api/download_queue')
                .then(response => response.json())
                .then(data => {
                    const items = Object.values(data);
                    updateProgressHeader(items);
                    const filteredItems = filterItems(items);
                    const sortedItems = sortItems(filteredItems);
                    renderTable(sortedItems);
                });
        }

        function clearItems() {
            fetch('/api/clear_items', {
                method: 'POST'
            })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Clear completed successful');
                    }
                });
        }

        function cancelItems() {
            fetch('/api/cancel_items', {
                method: 'POST'
            })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Cancel completed successful');
                    }
                });
        }

        function retryItems() {
            fetch('/api/retry_items', {
                method: 'POST'
            })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Retry completed successful');
                    }
                });
        }

        function restartWorkers() {
            fetch('/api/restart', {
                method: 'POST'
            })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Clear completed successful');
                    }
                });
        }

        function handleDelete(local_id) {
            fetch(`/api/delete/${local_id}`, {
                method: 'DELETE',
            })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Delete successful');
                    } else {
                        console.error('Delete failed:', data.error);
                    }
                })
                .catch(error => console.error('Error:', error));
        }

        function handleCancel(local_id) {
            fetch(`/api/cancel/${local_id}`, {
                method: 'POST',
            })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Cancel successful');
                    } else {
                        console.error('Cancel failed:', data.error);
                    }
                })
                .catch(error => console.error('Error:', error));
        }

        function handleRetry(local_id) {
            fetch(`/api/retry/${local_id}`, {
                method: 'POST',
            })
                .then(response => response.json())
                .then(data => {
                    if (data.success) {
                        console.log('Retry successful');
                    } else {
                        console.error('Retry failed:', data.error);
                    }
                })
                .catch(error => console.error('Error:', error));
        }


        

        function getActionButtonsHtml(item) {
            let buttons = '';
            if (config.download_copy_btn) {
                buttons += createButton('icons/link.png', 'Copy Link', `copyToClipboard('${item.item_url}')`, `${item.item_url}`);
            }
            if (!['Failed', 'Cancelled', 'Deleted', 'Already Exists', 'Downloaded'].includes(item.item_status)) {
                buttons += createButton('icons/stop.png', 'Stop Download', `handleCancel('${item.local_id}')`);
            }
            if (['Failed', 'Cancelled', 'Deleted'].includes(item.item_status)) {
                buttons += createButton('icons/retry.png', 'Retry Download', `handleRetry('${item.local_id}')`);
            }
            if (['Downloaded', 'Already Exists'].includes(item.item_status)) {
                if (config.download_open_btn) {
                    buttons += createButton('icons/file.png', 'Open File', `window.location.href='/api/download/${item.local_id}'`, `/api/download/${item.local_id}`);
                }
                if (config.download_delete_btn) {
                    buttons += createButton('icons/trash.png', 'Delete File', `handleDelete('${item.local_id}')`);
                }
            }
            return buttons;
        }


        function createRowElement(item) {
            const row = document.createElement('tr');
            row.dataset.localId = item.local_id;

            const localIdCell = document.createElement('td');
            localIdCell.style.display = 'none';
            localIdCell.dataset.localId = item.local_id;
            row.appendChild(localIdCell);

            // Conditionally create the cell for the image if thumbnails are enabled
            const itemImage = config.show_download_thumbnails && item.item_thumbnail
                ? `<img src="${item.item_thumbnail}" loading="lazy" style="width: {{ config.thumbnail_size }}px; height: {{ config.thumbnail_size }}px;">`
                : '';
            if (itemImage) {
                const cellImage = document.createElement('td');
                cellImage.innerHTML = itemImage;
                row.appendChild(cellImage);
            }

            const nameCell = document.createElement('td');
            nameCell.style.overflow = 'hidden';
            nameCell.style.textOverflow = 'ellipsis';
            nameCell.style.whiteSpace = 'nowrap';
            nameCell.textContent = item.item_name;
            row.appendChild(nameCell);

            const byCell = document.createElement('td');
            byCell.className = 'hide-on-mobile';
            byCell.textContent = capitalizeFirstLetter(item.parent_category) || 'N/A';
            row.appendChild(byCell);

            const serviceNameSpan = document.createElement('span');
            serviceNameSpan.className = 'hide-on-mobile';
            serviceNameSpan.textContent = formatServiceName(item.item_service);
            const serviceIcon = item.item_service ? `<img src="/icons/${item.item_service}.png" loading="lazy" style="width: 20px; height: 20px; margin-right: 5px;">` : '';
            const serviceCell = document.createElement('td');
            serviceCell.innerHTML = `${serviceIcon}`;
            serviceCell.appendChild(serviceNameSpan);
            row.appendChild(serviceCell);

            const statusCell = document.createElement('td');
            statusCell.style.whiteSpace = 'nowrap';
            statusCell.textContent = item.item_status || 'N/A';
            row.appendChild(statusCell);

            const progressCell = document.createElement('td');
            progressCell.className = 'hide-on-mobile';
            const progressValue = item.progress || 0;

            const progressContainer = document.createElement('div');
            progressContainer.style.cssText = 'width: 100%; background-color: #777777; border-radius: 5px; position: relative;';

            const progressBar = document.createElement('div');
            progressBar.style.cssText = `font-weight: bold; text-align: center; width: ${progressValue}%; background-color: #4caf50; height: 20px; border-radius: 5px; position: relative;`;
            progressBar.textContent = `${progressValue}%`;

            progressContainer.appendChild(progressBar);
            progressCell.appendChild(progressContainer);
            row.appendChild(progressCell);

            const actionsCell = document.createElement('td');
            actionsCell.style.whiteSpace = 'nowrap';
            const actionsHtml = getActionButtonsHtml(item);
            actionsCell.innerHTML = actionsHtml;
            actionsCell.dataset.actions = actionsHtml;
            row.appendChild(actionsCell);

            return row;
        }

        function updateRowElement(row, item) {
            // Update status
            const statusCell = row.cells[row.cells.length - 3];
            statusCell.textContent = item.item_status || 'N/A';

            // Update progress
            const progressCell = row.cells[row.cells.length - 2];
            const progressValue = item.progress || 0;
            const progressBar = progressCell.querySelector('div > div');
            if (progressBar) {
                progressBar.style.width = `${progressValue}%`;
                progressBar.textContent = `${progressValue}%`;
            }

            // Update actions
            const actionCell = row.cells[row.cells.length - 1];
            const newActions = getActionButtonsHtml(item);
            if (actionCell.dataset.actions !== newActions) {
                actionCell.innerHTML = newActions;
                actionCell.dataset.actions = newActions;
            }
        }

        // Sorting state
        let sortColumn = null;
        let sortDirection = 'asc';
        function setSort(column) {
            if (sortColumn === column) {
                sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
            } else {
                sortColumn = column;
                sortDirection = 'asc';
            }
            updateSortIndicators();
            fetchItems();
        }

        function updateSortIndicators() {
            const columns = ['item_name', 'parent_category', 'item_service', 'item_status', 'progress'];
            columns.forEach(col => {
                const indicator = document.getElementById('sort-indicator-' + col);
                if (indicator) {
                    if (sortColumn === col) {
                        indicator.textContent = sortDirection === 'asc' ? '▲' : '▼';
                    } else {
                        indicator.textContent = '\u00A0'; // non-breaking space
                    }
                }
            });
        }

        function updateProgressHeader(items) {
            const totalCount = items.length;
            const completedCount = items.filter(item => ['Downloaded', 'Already Exists', 'Cancelled'].includes(item.item_status)).length;
            const percentComplete = totalCount > 0 ? ((completedCount / totalCount) * 100).toFixed(2) : 0;
            document.getElementById('queue-status-message').textContent = `Total Items: ${completedCount}/${totalCount} | Progress: ${percentComplete}%`;    
        }

        function filterItems(items) {
            const filterData = returnFilterData();
            const passesFilter = (item) => {
                if (!filterData.download_queue_show_waiting && item.item_status === 'Waiting') return false;
                if (!filterData.download_queue_show_completed && (item.item_status === 'Downloaded' || item.item_status === 'Already Exists')) return false;
                if (!filterData.download_queue_show_cancelled && item.item_status === 'Cancelled') return false;
                if (!filterData.download_queue_show_failed && item.item_status === 'Failed') return false;
                if (!filterData.download_queue_show_unavailable && item.item_status === 'Unavailable') return false;
                return true;
            };
            return items.filter(passesFilter);
        }

        function sortItems(items) {
            if (!sortColumn) return items;

            return [...items].sort((a, b) => {
                let aVal = a[sortColumn];
                let bVal = b[sortColumn];
                // For progress, ensure numeric sort
                if (sortColumn === 'progress') {
                    aVal = Number(aVal) || 0;
                    bVal = Number(bVal) || 0;
                } else {
                    aVal = (aVal || '').toString().toLowerCase();
                    bVal = (bVal || '').toString().toLowerCase();
                }
                if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1;
                if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1;
                
                // Fall back to local_id when values are equal
                const aId = a.local_id || '';
                const bId = b.local_id || '';
                return aId.localeCompare(bId);
            });
        }

        function getExistingRows(tableBody) {
            const existingRows = new Map();
            for (const row of tableBody.querySelectorAll('tr')) {
                const localId = row.dataset.localId;
                if (localId) {
                    existingRows.set(localId, row);
                }
            }
            // Remove all rows from table
            while (tableBody.firstChild) {
                tableBody.removeChild(tableBody.firstChild);
            }
            return existingRows;
        }

        function renderTable(items) {
            const tableBody = document.getElementById('download-queue-table');
            const existingRows = getExistingRows(tableBody);
            for (const item of items) {
                let row;
                if (existingRows.has(item.local_id)) {
                    row = existingRows.get(item.local_id);
                    updateRowElement(row, item);
                } else {
                    row = createRowElement(item);
                }
                tableBody.appendChild(row);
            }
        }

        window.onload = function () {
            updateSortIndicators();
            fetchItems();
        };
        setInterval(fetchItems, 2000);
    </script>
</body>

</html>