function byId(id) {
    return document.getElementById(id);
}

function getToolUrl(extraParams) {
    var url = new URL(window.location.href);
    url.search = '';

    if (extraParams) {
        Object.keys(extraParams).forEach(function(key) {
            var value = extraParams[key];
            if (value !== undefined && value !== null) {
                url.searchParams.set(key, value);
            }
        });
    }

    return url.toString();
}

function getRows() {
    return Array.prototype.slice.call(document.querySelectorAll('#tb tr')).filter(function(tr) {
        return !tr.classList.contains('empty');
    });
}

function getRowByDomain(domain) {
    return document.querySelector('tr[data-domain="' + cssEscape(domain) + '"]');
}

function getEffectiveStatus(tr) {
    return tr.getAttribute('data-status') || 'pending';
}

function scoreClass(value) {
    if (value === '' || value === null || value === undefined || isNaN(Number(value))) {
        return 'score-na';
    }

    value = Number(value);

    if (value >= 90) return 'score-good';
    if (value >= LIGHTHOUSE_FAIL_THRESHOLD) return 'score-mid';
    return 'score-bad';
}

function formatScoreJs(value) {
    return (value === '' || value === null || value === undefined || isNaN(Number(value))) ? '—' : String(value);
}

function setScoreCell(td, value) {
    td.textContent = formatScoreJs(value);
    td.classList.remove('score-good', 'score-mid', 'score-bad', 'score-na');
    td.classList.add(scoreClass(value));
}

function extractSortValue(tr, key) {
    if (key === 'domain') {
        return (tr.getAttribute('data-domain') || '').toLowerCase();
    }

    if (key === 'status') {
        return getEffectiveStatus(tr).toLowerCase();
    }

    if (key === 'scanned') {
        return (tr.getAttribute('data-scanned') || '').toLowerCase();
    }

    var raw = tr.getAttribute('data-' + key + '-' + CURRENT_DEVICE);
    return raw === '' || raw === null ? -1 : Number(raw);
}

function buildModeButtons() {
    if (!BOTH_MODES) {
        return '';
    }

    return ''
        + '<div class="modebar">'
        + '<button class="' + (ACTIVE_POPUP_MODE === 'mobile' ? 'active' : '') + '" onclick="switchPopupMode(\'mobile\')">Mobile</button>'
        + '<button class="' + (ACTIVE_POPUP_MODE === 'desktop' ? 'active' : '') + '" onclick="switchPopupMode(\'desktop\')">Desktop</button>'
        + '</div>';
}

function buildCategoryButtons() {
    var html = '<div class="tabbar">';

    CATEGORY_KEYS.forEach(function(category) {
        html += '<button class="' + (ACTIVE_POPUP_CATEGORY === category ? 'active' : '') + '" onclick="switchPopupCategory(\'' + category + '\')">';
        html += escapeHtml(CATEGORY_LABELS[category]);
        html += '</button>';
    });

    html += '</div>';
    return html;
}

function buildScoreCards(row) {
    var html = '<div class="audit-grid">';

    CATEGORY_KEYS.forEach(function(category) {
        var column = CATEGORY_COLUMN_MAP[category];
        var attr = 'data-' + column + '-' + ACTIVE_POPUP_MODE;
        var value = row ? row.getAttribute(attr) : '';

        html += '<div class="audit-score">';
        html += '<div class="n ' + scoreClass(value) + '">' + formatScoreJs(value) + '</div>';
        html += '<div class="l">' + escapeHtml(CATEGORY_LABELS[category]) + '</div>';
        html += '</div>';
    });

    html += '</div>';
    return html;
}

function buildAuditList(items, isWarning) {
    var html = '';

    items.forEach(function(audit) {
        html += '<div class="audit-item' + (isWarning ? ' warn' : '') + '">';

        if (isWarning) {
            html += '<div class="audit-title">Manual review: ' + escapeHtml(audit.title || 'Untitled audit') + '</div>';
        } else {
            html += '<div class="audit-title">' + escapeHtml(audit.title || 'Untitled audit') + '</div>';

            if (audit.displayValue) {
                html += '<div class="audit-val">' + escapeHtml(audit.displayValue) + '</div>';
            }
        }

        if (audit.description) {
            html += '<div class="audit-desc">' + escapeHtml(audit.description) + '</div>';
        }

        html += '</div>';
    });

    return html;
}

function changeScope(value) {
    var url = new URL(window.location.href);

    if (value === 'all') {
        url.searchParams.set('all', '1');
    } else {
        url.searchParams.delete('all');
    }

    window.location.href = url.toString();
}

function applyFilters() {
    var query = (byId('srch')?.value || '').toLowerCase();
    var statusFilter = byId('fSt')?.value || '';
    var visible = 0;

    getRows().forEach(function(tr) {
        var domain = (tr.getAttribute('data-domain') || '').toLowerCase();
        var status = getEffectiveStatus(tr);

        var show = true;

        if (query && domain.indexOf(query) === -1) {
            show = false;
        }

        if (statusFilter && status !== statusFilter) {
            show = false;
        }

        tr.style.display = show ? '' : 'none';

        if (show) {
            visible++;
        }
    });

    var rc = byId('rc');
    if (rc) {
        rc.textContent = visible + ' shown';
    }
}

function switchDevice(mode) {
    CURRENT_DEVICE = mode;

    var deviceSelect = byId('fDevice');
    if (deviceSelect && deviceSelect.value !== mode) {
        deviceSelect.value = mode;
    }

    getRows().forEach(function(tr) {
        var cells = tr.querySelectorAll('td');
        var attrName = mode === 'mobile' ? 'data-score-mobile' : 'data-score-desktop';

        [2, 3, 4, 5].forEach(function(idx) {
            var td = cells[idx];
            if (!td) {
                return;
            }

            setScoreCell(td, td.getAttribute(attrName));
        });
    });

    applyFilters();
}

function sortBy(index, key) {
    var sameKey = CURRENT_SORT_KEY === key;
    CURRENT_SORT_DIR = sameKey ? (CURRENT_SORT_DIR === 'asc' ? 'desc' : 'asc') : 'asc';
    CURRENT_SORT_KEY = key;
    CURRENT_SORT_INDEX = index;

    var tbody = byId('tb');
    var rows = getRows();

    rows.sort(function(a, b) {
        var av = extractSortValue(a, key);
        var bv = extractSortValue(b, key);

        if (av < bv) return CURRENT_SORT_DIR === 'asc' ? -1 : 1;
        if (av > bv) return CURRENT_SORT_DIR === 'asc' ? 1 : -1;
        return 0;
    });

    rows.forEach(function(row) {
        tbody.appendChild(row);
    });

    applyFilters();
}

function doExport(format) {
    var params = {
        action: format === 'csv' ? 'export_csv' : 'export_json'
    };

    if (byId('fScope')?.value === 'all') {
        params.all = '1';
    }

    window.location.href = getToolUrl(params);
}

function resetScan(btn, sid) {
    btn.disabled = true;

    fetch(getToolUrl({
        action: 'reset_scan',
        sid: String(sid)
    }))
        .then(function(response) {
            return response.json();
        })
        .then(function(data) {
            if (data && data.ok) {
                window.location.reload();
                return;
            }

            btn.disabled = false;
            alert((data && data.error) ? data.error : 'Reset failed.');
        })
        .catch(function() {
            btn.disabled = false;
            alert('Reset failed.');
        });
}

function openPopup(domain) {
    ACTIVE_POPUP_DOMAIN = domain;
    ACTIVE_POPUP_MODE = CURRENT_DEVICE;
    ACTIVE_POPUP_CATEGORY = 'performance';

    var row = getRowByDomain(domain);
    var scanned = row ? row.getAttribute('data-scanned') : '';

    byId('ov').classList.add('show');
    byId('popTitle').textContent = domain;
    byId('popMeta').textContent = scanned ? ('Last scanned: ' + scanned) : 'Not yet scanned';
    byId('popBody').innerHTML = '<p class="loading">Loading...</p>';

    loadPopupData(domain, ACTIVE_POPUP_MODE).then(function() {
        renderPopup(row);
    });
}

function loadPopupData(domain, mode) {
    var cacheKey = domain + '::' + mode;

    if (POPUP_CACHE[cacheKey]) {
        return Promise.resolve(POPUP_CACHE[cacheKey]);
    }

    return fetch(getToolUrl({
        action: 'detail',
        domain: domain,
        mode: mode
    }))
        .then(function(response) {
            return response.json();
        })
        .then(function(data) {
            POPUP_CACHE[cacheKey] = data;
            return data;
        })
        .catch(function() {
            POPUP_CACHE[cacheKey] = { error: 'Failed to load Lighthouse detail.' };
            return POPUP_CACHE[cacheKey];
        });
}

function renderPopup(row) {
    var data = POPUP_CACHE[ACTIVE_POPUP_DOMAIN + '::' + ACTIVE_POPUP_MODE] || {};
    var body = byId('popBody');

    if (data.error) {
        body.innerHTML = '<p class="none">' + escapeHtml(data.error) + '</p>';
        return;
    }

    var audits = ((data.audits || {})[ACTIVE_POPUP_CATEGORY]) || [];
    var incomplete = ((data.incomplete || {})[ACTIVE_POPUP_CATEGORY]) || [];
    var scoreValue = (data.scores || {})[ACTIVE_POPUP_CATEGORY];

    var html = '';
    html += buildScoreCards(row);
    html += buildModeButtons();
    html += buildCategoryButtons();

    if (!audits.length && !incomplete.length) {
        if (scoreValue === null || scoreValue === undefined) {
            html += '<p class="none">No data available for this category.</p>';
        } else {
            html += '<p class="none">No issues found for this category.</p>';
        }

        body.innerHTML = html;
        return;
    }

    html += buildAuditList(audits, false);
    html += buildAuditList(incomplete, true);

    body.innerHTML = html;
}

function switchPopupMode(mode) {
    ACTIVE_POPUP_MODE = mode;

    loadPopupData(ACTIVE_POPUP_DOMAIN, mode).then(function() {
        renderPopup(getRowByDomain(ACTIVE_POPUP_DOMAIN));
    });
}

function switchPopupCategory(category) {
    ACTIVE_POPUP_CATEGORY = category;
    renderPopup(getRowByDomain(ACTIVE_POPUP_DOMAIN));
}

function closePopup(event) {
    if (event && event.target && event.target.id !== 'ov') {
        return;
    }

    byId('ov').classList.remove('show');
}

function cssEscape(str) {
    if (window.CSS && CSS.escape) {
        return CSS.escape(str);
    }

    return str.replace(/([ #;?%&,.+*~\':"!^$\[\]()=>|\/])/g, '\\$1');
}

function escapeHtml(str) {
    return String(str || '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}

document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') {
        closePopup();
    }
});

document.addEventListener('DOMContentLoaded', function() {
    setTheme();
    showBody();
    initEventButtons();

    var deviceSelect = byId('fDevice');
    if (deviceSelect) {
        deviceSelect.value = CURRENT_DEVICE;
    }

    applyFilters();
});