<?php

function findLoader(): string {
    $dir = __DIR__;
    for ($i = 0; $i < 6; $i++) {
        $candidate = $dir . '/lib/php/loader.php';
        if (file_exists($candidate)) {
            return $candidate;
        }
        $dir = dirname($dir);
    }
    die("Could not locate loader.php. Ensure this tool is installed within the WMD SED directory tree.\n");
}
require findLoader();

use CodePunch\Base\Util as UTIL;

// =============================================================================
// TOOL CONSTANTS
// =============================================================================

define('THIS_TOOL_NAME', 'lighthouse');
define('LIGHTHOUSE_CONFIG_KEY', str_replace('-', '_', THIS_TOOL_NAME) . '_tool');

// =============================================================================
// LIGHTHOUSE CONSTANTS - must match lighthouse-gather.php
// =============================================================================

const LIGHTHOUSE_OUTPUT_FOLDER    = 'lh-data';
const LIGHTHOUSE_FAIL_THRESHOLD   = 50;
const LIGHTHOUSE_DEFAULT_CATEGORY = 'Lighthouse Test Domains';
const COL_STATUS                  = 'lh_status';
const COL_SCANNED_AT              = 'lh_scanned_at';
const COL_PERF_MOBILE             = 'lh_perf_mobile';
const COL_SEO_MOBILE              = 'lh_seo_mobile';
const COL_A11Y_MOBILE             = 'lh_a11y_mobile';
const COL_BP_MOBILE               = 'lh_bp_mobile';
const COL_PERF_DESKTOP            = 'lh_perf_desktop';
const COL_SEO_DESKTOP             = 'lh_seo_desktop';
const COL_A11Y_DESKTOP            = 'lh_a11y_desktop';
const COL_BP_DESKTOP              = 'lh_bp_desktop';

require_once 'includes/base-init.php';

// =============================================================================
// CLI GUARD
// =============================================================================

if (UTIL::is_cli()) {
    UTIL::print('This tool must be run in a browser.');
    exit;
}

// =============================================================================
// AUTH + SESSION
// =============================================================================

$auth = new \CodePunch\Config\Auth(\CodePunch\DB\Database::STANDARD_INIT);
if (!$auth) {
    header('Location: ../index.php?logout&return=tools/lighthouse');
    exit;
}
$hasProClass = $auth->getProClass(THIS_TOOL_NAME);
$requiresPro = $auth->hasProClass(THIS_TOOL_NAME, true);
if(!$hasProClass && $requiresPro) {
	header("Location: ../tools/");
    exit;
}

$sessionStatus = $auth->validateSession(false, false);
$isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) || (isset($_GET['action']) && $_GET['action'] !== '');

if ($sessionStatus !== \CodePunch\Config\Auth::VALID) {
    if ($isAjax) {
        header('Content-Type: application/json');
        echo json_encode([
            'error'   => 'session_expired',
            'message' => 'Your session has expired. Please log in again.'
        ]);
        exit;
    }

    header('Location: ../index.php?logout&return=tools/lighthouse');
    exit;
}

if (!\CodePunch\Config\Auth::isAdmin()) {
    if ($isAjax) {
        header('Content-Type: application/json');
        echo json_encode([
            'error'   => 'auth_required',
            'message' => 'Administrator access required.'
        ]);
        exit;
    }

    UTIL::print('Access denied. Administrator privileges required.');
    exit;
}

$db = $auth->getDatabase();
if (!$db) {
    UTIL::print('Database connection failed.');
    exit;
}

// =============================================================================
// REQUEST STATE
// =============================================================================

$rd    = UTIL::get_unsafe_request_data_array();
$table = $db->getDomainTableName();
$action = isset($rd['action']) ? trim($rd['action']) : '';

// =============================================================================
// PATHS
// =============================================================================

$logBase   = UTIL::get_log_folder_path();
$outFolder = rtrim($logBase, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . LIGHTHOUSE_OUTPUT_FOLDER . DIRECTORY_SEPARATOR;

// =============================================================================
// COLUMN CHECK
// =============================================================================

$allColumns   = $db->getDetailsOfAllDomainColumns();
$columnsReady = isset($allColumns[COL_STATUS]) && isset($allColumns[COL_SCANNED_AT]);
$gatherPath   = str_replace('lighthouse.php', 'lighthouse' . DIRECTORY_SEPARATOR . 'lighthouse-gather.php', __FILE__);

// =============================================================================
// ACTION HANDLERS
// =============================================================================

if ($action === 'detail') {
    header('Content-Type: application/json');

    $domain = preg_replace('/[^a-z0-9.\-]/', '', strtolower($rd['domain'] ?? ''));
    $mode   = in_array($rd['mode'] ?? '', ['mobile', 'desktop'], true) ? $rd['mode'] : 'mobile';

    if ($domain === '') {
        echo json_encode(['error' => 'No domain specified.']);
        exit;
    }

    $jsonFile = $outFolder . $domain . '-' . $mode . '.json';
    if (!file_exists($jsonFile)) {
        echo json_encode(['error' => 'No scan file found for: ' . $domain . ' (' . $mode . ')']);
        exit;
    }

    $raw = file_get_contents($jsonFile);
    if ($raw === false) {
        echo json_encode(['error' => 'Could not read scan file.']);
        exit;
    }

    echo $raw;
    exit;
}

if ($action === 'export_json') {
    header('Content-Type: application/json');
    header('Content-Disposition: attachment; filename="lighthouse-export-' . date('Y-m-d') . '.json"');

    $showAllExport = isset($rd['all']) && $rd['all'] === '1';
    $exportRows = fetchAllRows($db, $table, $showAllExport ? [] : resolveCategorySids($db));
    $export = [];

    foreach ($exportRows as $row) {
        $entry = $row;
        foreach (['mobile', 'desktop'] as $mode) {
            $jsonFile = $outFolder . $row['domain'] . '-' . $mode . '.json';
            if (file_exists($jsonFile)) {
                $entry['detail_' . $mode] = json_decode(file_get_contents($jsonFile), true);
            }
        }
        $export[] = $entry;
    }

    echo json_encode($export, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    exit;
}

if ($action === 'export_csv') {
    header('Content-Type: text/csv');
    header('Content-Disposition: attachment; filename="lighthouse-export-' . date('Y-m-d') . '.csv"');

    $showAllExport = isset($rd['all']) && $rd['all'] === '1';
    $exportRows = fetchAllRows($db, $table, $showAllExport ? [] : resolveCategorySids($db));

    $out = fopen('php://output', 'w');
    fputcsv($out, ['Domain', 'Status', 'Perf (M)', 'SEO (M)', 'A11y (M)', 'BP (M)', 'Perf (D)', 'SEO (D)', 'A11y (D)', 'BP (D)', 'Scanned At']);

    foreach ($exportRows as $row) {
        fputcsv($out, [
            $row['domain'],
            $row[COL_STATUS] ?? '',
            $row[COL_PERF_MOBILE] ?? '',
            $row[COL_SEO_MOBILE] ?? '',
            $row[COL_A11Y_MOBILE] ?? '',
            $row[COL_BP_MOBILE] ?? '',
            $row[COL_PERF_DESKTOP] ?? '',
            $row[COL_SEO_DESKTOP] ?? '',
            $row[COL_A11Y_DESKTOP] ?? '',
            $row[COL_BP_DESKTOP] ?? '',
            $row[COL_SCANNED_AT] ?? '',
        ]);
    }

    fclose($out);
    exit;
}

if ($action === 'reset_scan') {
    header('Content-Type: application/json');

    $sid = isset($rd['sid']) ? (int)$rd['sid'] : 0;
    if ($sid <= 0) {
        echo json_encode(['error' => 'Invalid domain ID.']);
        exit;
    }

    $result = $db->updateTable($table, [COL_SCANNED_AT => null], 'sid=?', [$sid]);

    if ($result === false) {
        echo json_encode(['error' => 'Database update failed.']);
    } else {
        echo json_encode(['ok' => true, 'sid' => $sid]);
    }

    exit;
}

// =============================================================================
// MAIN PAGE DATA
// =============================================================================

$showAll      = isset($rd['all']) && $rd['all'] === '1';
$categorySids = $showAll ? [] : resolveCategorySids($db);
if (!$columnsReady) {
    $rows = [];
} elseif ($showAll) {
    $rows = fetchAllRows($db, $table);
} elseif (empty($categorySids)) {
    $rows = [];
} else {
    $rows = fetchAllRows($db, $table, $categorySids);
}
$missingCategory = !$showAll && empty($categorySids);
$stats        = $columnsReady ? buildStats($rows) : [];
$hasMobile    = hasAnyModeData($rows, 'mobile');
$hasDesktop   = hasAnyModeData($rows, 'desktop');
$bothModes    = $hasMobile && $hasDesktop;

?><!DOCTYPE HTML>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <base href="<?php echo $baseUrl; ?>">
    <link rel="shortcut icon" type="image/x-icon" href="lib/layouts/images/favicon.ico">
    <meta name="author" content="">
    <title>Watch My Domains Server Edition v6</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <meta name="dcterms.rightsHolder" content="Softnik Technologies">

    <link rel="preload" as="font" href="lib/layouts/fonts/Quicksand/quicksand-v28-latin-regular.woff2" type="font/woff2" crossorigin="anonymous">
    <link rel="preload" as="font" href="lib/layouts/fonts/Roboto-Slab/roboto-slab-v22-latin-regular.woff2" type="font/woff2" crossorigin="anonymous">
    <link rel="preload" as="font" href="lib/layouts/fonts/Josefin-Sans/josefin-sans-v23-latin-regular.woff2" type="font/woff2" crossorigin="anonymous">
    <link rel="preload" as="font" href="lib/layouts/fonts/Quicksand/quicksand-v28-latin-700.woff2" type="font/woff2" crossorigin="anonymous">
    <link rel="preload" as="font" href="lib/layouts/fonts/Roboto-Slab/roboto-slab-v22-latin-700.woff2" type="font/woff2" crossorigin="anonymous">
    <link rel="preload" as="font" href="lib/layouts/fonts/Josefin-Sans/josefin-sans-v23-latin-600.woff2" type="font/woff2" crossorigin="anonymous">
    <link rel="preload" as="font" href="lib/layouts/fonts/Open-Sans/open-sans-v40-greek_hebrew_latin_vietnamese-regular.woff2" type="font/woff2" crossorigin="anonymous">
    <link rel="preload" as="font" href="lib/layouts/fonts/Open-Sans/open-sans-v40-greek_hebrew_latin_vietnamese-700.woff2" type="font/woff2" crossorigin="anonymous">

    <link href="lib/layouts/fonts/Quicksand/fonts.css" rel="stylesheet">
    <link href="lib/layouts/fonts/Roboto-Slab/fonts.css" rel="stylesheet">
    <link href="lib/layouts/fonts/Josefin-Sans/fonts.css" rel="stylesheet">
    <link href="lib/layouts/fonts/Open-Sans/fonts.css" rel="stylesheet">
    <link href="lib/layouts/css/min/common.min.css" rel="stylesheet">
    <link href="lib/layouts/modules/common/css/min/common.min.css" rel="stylesheet">

    <script src="api.php?c=js&file=data.js&loc=modules/toolbox" type="text/javascript"></script>

    <link rel="stylesheet" type="text/css" href="lib/layouts/colors/light/light.css" id="theme-mode-css">
    <link rel="stylesheet" type="text/css" href="lib/layouts/colors/light/themes/Default/default.css" id="theme-default-css">
    <link rel="stylesheet" type="text/css" href="lib/layouts/colors/light/themes/Default/styles.css" id="theme-styles-css">
    <link rel="stylesheet" type="text/css" href="lib/php/styles.php" id="theme-bg-css">

    <link href="tools/css/common.css" rel="stylesheet">
    <link href="tools/css/common-dark.css" rel="stylesheet">
    <link href="tools/css/toggle.css" rel="stylesheet">
	<link href="tools/css/lighthouse.css" rel="stylesheet">
</head>
<body>

<div class="theme-select theme-bg" id="themechange"></div>
<div class="menu-select theme-bg" id="menuselect"></div>

<div id="contentwrap">
	<?php include("includes/head-logo-toolbar.php"); ?>

    <div id="content">
        <div id="maincontent">
            <div id="domaindata">
                <div class="lh-panel">

                    <div class="panel-header">
                        <h1>Lighthouse Monitor</h1>
						<div class="lh-subtitle">Review Lighthouse performance, SEO, accessibility, and best-practice results across your monitored domains.</div>
                    </div>

                    <div class="wrap">
					
						<?php if ($columnsReady && $missingCategory): ?>
							<div class="setup-notice">
								<strong>No Lighthouse category domains found.</strong>
								Scans run only for domains assigned to the category
								<strong><?php echo htmlspecialchars(LIGHTHOUSE_DEFAULT_CATEGORY); ?></strong>.
								Create that category in WMD SED and assign domains to it, or switch to
								<strong>Show All Domains</strong> to view all rows.
							</div>
						<?php endif; ?>

                        <?php if (!$columnsReady): ?>
                            <div class="setup-notice">
                                <strong>Setup required.</strong> The Lighthouse columns do not exist yet. Run this command, then refresh this page.
                                <code>php <?php echo htmlspecialchars($gatherPath); ?> --setup-columns</code>
                            </div>
                        <?php else: ?>

                            <div class="score-stats">
                                <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_mobile']['perf'] ?? null); ?>"><?php echo formatScore($stats['avg_mobile']['perf'] ?? null); ?></div><div class="l">Perf (Mobile)</div></div>
                                <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_mobile']['seo'] ?? null); ?>"><?php echo formatScore($stats['avg_mobile']['seo'] ?? null); ?></div><div class="l">SEO (Mobile)</div></div>
                                <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_mobile']['a11y'] ?? null); ?>"><?php echo formatScore($stats['avg_mobile']['a11y'] ?? null); ?></div><div class="l">A11y (Mobile)</div></div>
                                <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_mobile']['bp'] ?? null); ?>"><?php echo formatScore($stats['avg_mobile']['bp'] ?? null); ?></div><div class="l">BP (Mobile)</div></div>
                                <?php if ($hasDesktop): ?>
                                    <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_desktop']['perf'] ?? null); ?>"><?php echo formatScore($stats['avg_desktop']['perf'] ?? null); ?></div><div class="l">Perf (Desktop)</div></div>
                                    <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_desktop']['seo'] ?? null); ?>"><?php echo formatScore($stats['avg_desktop']['seo'] ?? null); ?></div><div class="l">SEO (Desktop)</div></div>
                                    <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_desktop']['a11y'] ?? null); ?>"><?php echo formatScore($stats['avg_desktop']['a11y'] ?? null); ?></div><div class="l">A11y (Desktop)</div></div>
                                    <div class="sc"><div class="n <?php echo scoreNumberClass($stats['avg_desktop']['bp'] ?? null); ?>"><?php echo formatScore($stats['avg_desktop']['bp'] ?? null); ?></div><div class="l">BP (Desktop)</div></div>
                                <?php endif; ?>
                            </div>

                            <div class="stats">
                                <div class="sc"><div class="n"><?= $stats['total'] ?></div><div class="l">Total</div></div>
                                <div class="sc"><div class="n"><?= $stats['scanned'] ?></div><div class="l">Scanned</div></div>
                                <div class="sc"><div class="n cn-pass"><?= $stats['pass'] ?></div><div class="l">Pass</div></div>
                                <div class="sc"><div class="n cn-fail"><?= $stats['fail'] ?></div><div class="l">Fail</div></div>
                                <div class="sc"><div class="n cn-grey"><?= $stats['error'] ?></div><div class="l">Error</div></div>
                                <div class="sc"><div class="n cn-grey"><?= $stats['not_scanned'] ?></div><div class="l">Not Scanned</div></div>
                            </div>

							<div class="toolbar">
								<input type="text" id="srch" placeholder="Filter domains..." oninput="applyFilters()">

								<select id="fScope" onchange="changeScope(this.value)">
									<option value="category" <?= $showAll ? '' : 'selected' ?>>Lighthouse Category Only</option>
									<option value="all" <?= $showAll ? 'selected' : '' ?>>Show All Domains</option>
								</select>

								<select id="fSt" onchange="applyFilters()">
									<option value="">All statuses</option>
									<option value="pass">Pass</option>
									<option value="fail">Fail</option>
									<option value="error">Error</option>
									<option value="pending">Not Scanned</option>
								</select>

								<?php if ($bothModes): ?>
									<select id="fDevice" onchange="switchDevice(this.value)">
										<option value="mobile" selected>Mobile</option>
										<option value="desktop">Desktop</option>
									</select>
								<?php endif; ?>

								<span class="rc" id="rc"></span>
								<button class="btn" onclick="doExport('csv')">&#8595; CSV</button>
								<button class="btn" onclick="doExport('json')">&#8595; JSON</button>
							</div>

                            <div class="tbl-wrap">
                                <table>
                                    <thead>
                                        <tr>
                                            <th onclick="sortBy(0, 'domain')">Domain<span class="sa" id="sa0"></span></th>
                                            <th onclick="sortBy(1, 'status')">Status<span class="sa" id="sa1"></span></th>
                                            <th onclick="sortBy(2, 'perf')">Performance<span class="sa" id="sa2"></span></th>
                                            <th onclick="sortBy(3, 'seo')">SEO<span class="sa" id="sa3"></span></th>
                                            <th onclick="sortBy(4, 'a11y')">Accessibility<span class="sa" id="sa4"></span></th>
                                            <th onclick="sortBy(5, 'bp')">Best Practices<span class="sa" id="sa5"></span></th>
                                            <th onclick="sortBy(6, 'scanned')">Scanned At<span class="sa" id="sa6"></span></th>
                                            <th style="width: 36px"></th>
                                        </tr>
                                    </thead>
                                    <tbody id="tb">
                                    <?php if (empty($rows)): ?>
                                        <tr class="empty">
											<td colspan="8">
												<?php if ($missingCategory): ?>
													No domains are currently assigned to the <?php echo htmlspecialchars(LIGHTHOUSE_DEFAULT_CATEGORY); ?> category.
												<?php else: ?>
													No scan data found. Run lighthouse-gather.php to begin.
												<?php endif; ?>
											</td>
										</tr>
                                    <?php else: ?>
                                    <?php foreach ($rows as $rawRow): ?>
										<?php $row = prepareRow($rawRow); ?>
										<tr onclick="openPopup(<?= htmlspecialchars(json_encode($row['domain']), ENT_QUOTES) ?>)"
											data-domain="<?= htmlspecialchars($row['domain']) ?>"
											data-status="<?= htmlspecialchars($row['status']) ?>"
											data-sid="<?= $row['sid'] ?>"
											data-perf-mobile="<?= htmlspecialchars((string)$row['perf_mobile']) ?>"
											data-seo-mobile="<?= htmlspecialchars((string)$row['seo_mobile']) ?>"
											data-a11y-mobile="<?= htmlspecialchars((string)$row['a11y_mobile']) ?>"
											data-bp-mobile="<?= htmlspecialchars((string)$row['bp_mobile']) ?>"
											data-perf-desktop="<?= htmlspecialchars((string)$row['perf_desktop']) ?>"
											data-seo-desktop="<?= htmlspecialchars((string)$row['seo_desktop']) ?>"
											data-a11y-desktop="<?= htmlspecialchars((string)$row['a11y_desktop']) ?>"
											data-bp-desktop="<?= htmlspecialchars((string)$row['bp_desktop']) ?>"
											data-scanned="<?= htmlspecialchars($row['scannedAt']) ?>">
											<td><?= htmlspecialchars($row['domain']) ?></td>
											<td><?= $row['status'] ? '<span class="badge ' . $row['statusBadgeClass'] . '">' . htmlspecialchars($row['status']) . '</span>' : '<span class="badge be">pending</span>' ?></td>
											<td class="<?= scoreCellClass($row['perf_mobile']) ?>" data-score-mobile="<?= $row['perf_mobile'] === null ? '' : (int)$row['perf_mobile'] ?>" data-score-desktop="<?= $row['perf_desktop'] === null ? '' : (int)$row['perf_desktop'] ?>"><?= formatScore($row['perf_mobile']) ?></td>
											<td class="<?= scoreCellClass($row['seo_mobile']) ?>" data-score-mobile="<?= $row['seo_mobile'] === null ? '' : (int)$row['seo_mobile'] ?>" data-score-desktop="<?= $row['seo_desktop'] === null ? '' : (int)$row['seo_desktop'] ?>"><?= formatScore($row['seo_mobile']) ?></td>
											<td class="<?= scoreCellClass($row['a11y_mobile']) ?>" data-score-mobile="<?= $row['a11y_mobile'] === null ? '' : (int)$row['a11y_mobile'] ?>" data-score-desktop="<?= $row['a11y_desktop'] === null ? '' : (int)$row['a11y_desktop'] ?>"><?= formatScore($row['a11y_mobile']) ?></td>
											<td class="<?= scoreCellClass($row['bp_mobile']) ?>" data-score-mobile="<?= $row['bp_mobile'] === null ? '' : (int)$row['bp_mobile'] ?>" data-score-desktop="<?= $row['bp_desktop'] === null ? '' : (int)$row['bp_desktop'] ?>"><?= formatScore($row['bp_mobile']) ?></td>
											<td><?= htmlspecialchars($row['scannedAt']) ?: '—' ?></td>
											<td class="reset-col">
												<button
													class="btn-reset"
													title="Reset scan date - will be re-scanned on next run"
													onclick="event.stopPropagation();resetScan(this,<?= $row['sid'] ?>)"
												>&#x21BA;</button>
											</td>
										</tr>
									<?php endforeach; ?>
                                    <?php endif; ?>
                                    </tbody>
                                </table>
                            </div>

                        <?php endif; ?>

                    </div>
                </div>
            </div>
        </div>
    </div>

</div>

<div class="overlay" id="ov" onclick="closePopup(event)">
    <div class="popup" onclick="event.stopPropagation()">
        <div class="pop-hd">
            <div>
                <h2 id="popTitle">Loading...</h2>
                <div class="pop-meta" id="popMeta"></div>
            </div>
            <button class="pop-close" onclick="closePopup()" title="Close (Esc)">&#x2715;</button>
        </div>
        <div class="pop-body" id="popBody">
            <p class="loading">Loading...</p>
        </div>
    </div>
</div>

<script>
var baseurl           = "<?php echo $baseUrl; ?>";
var API_BASE_URL      = <?php echo json_encode(htmlspecialchars($apiBaseUrl, ENT_QUOTES, 'UTF-8')); ?>;
var IS_ADMIN          = <?php echo $isAdmin ? 'true' : 'false'; ?>;
var CURRENT_USER      = <?php echo json_encode($currentUserName); ?>;
var LIGHTHOUSE_CONFIG_KEY = "<?php echo LIGHTHOUSE_CONFIG_KEY; ?>";
var CONFIG_CREATED_AT = <?php echo time(); ?>;
var LIGHTHOUSE_FAIL_THRESHOLD = <?php echo (int)LIGHTHOUSE_FAIL_THRESHOLD; ?>;
var BOTH_MODES = <?php echo $bothModes ? 'true' : 'false'; ?>;
var CURRENT_DEVICE = 'mobile';
var CURRENT_SORT_INDEX = 0;
var CURRENT_SORT_KEY = 'domain';
var CURRENT_SORT_DIR = 'asc';
var ACTIVE_POPUP_DOMAIN = '';
var ACTIVE_POPUP_MODE = 'mobile';
var ACTIVE_POPUP_CATEGORY = 'performance';
var POPUP_CACHE = {};
var CATEGORY_LABELS = {
    performance: 'Performance',
    seo: 'SEO',
    accessibility: 'Accessibility',
    'best-practices': 'Best Practices'
};
var CATEGORY_KEYS = ['performance', 'seo', 'accessibility', 'best-practices'];
var CATEGORY_COLUMN_MAP = {
    performance: 'perf',
    seo: 'seo',
    accessibility: 'a11y',
    'best-practices': 'bp'
};

</script>

<script type="text/javascript" src="tools/js/common.js"></script>
<script type="text/javascript" src="tools/js/lighthouse.js"></script>

</body>
</html>

<?php

// =============================================================================
// FUNCTIONS
// =============================================================================

function resolveCategorySids($db): array {
    $cid = $db->findOneOf($db->getCategoryTableName(), 'name', LIGHTHOUSE_DEFAULT_CATEGORY, 'cid');
    if (!$cid) {
        return [];
    }

    $connRows = $db->getFromTable(
        'did',
        $db->getCategoryConnectionTableName(),
        'cid = ?',
        [(int)$cid],
        '',
        '',
        100000
    );

    if ($connRows === false || empty($connRows)) {
        return [];
    }
	$connRows = array_map(fn($row) => array_change_key_case($row, CASE_LOWER), $connRows);
    return array_map(fn($r) => (int)$r['did'], $connRows);
}

function fetchAllRows($db, string $table, array $sids = []): array {
    $columns = implode(',', [
        'sid',
        'domain',
        COL_STATUS,
        COL_SCANNED_AT,
        COL_PERF_MOBILE,
        COL_SEO_MOBILE,
        COL_A11Y_MOBILE,
        COL_BP_MOBILE,
        COL_PERF_DESKTOP,
        COL_SEO_DESKTOP,
        COL_A11Y_DESKTOP,
        COL_BP_DESKTOP,
    ]);

    if (!empty($sids)) {
        $placeholders = implode(',', array_fill(0, count($sids), '?'));
        $rows = $db->getFromTable($columns, $table, "sid IN ($placeholders)", $sids, 'domain', 'asc', 100000);
    } else {
        $rows = $db->getFromTable($columns, $table, '1=1', [], 'domain', 'asc', 100000);
    }

    if ($rows === false) {
        return [];
    }
	$rows = array_map(fn($row) => array_change_key_case($row, CASE_LOWER), $rows);
    return $rows;
}

function hasAnyModeData(array $rows, string $mode): bool {
    $columns = [
        'mobile' => [COL_PERF_MOBILE, COL_SEO_MOBILE, COL_A11Y_MOBILE, COL_BP_MOBILE],
        'desktop' => [COL_PERF_DESKTOP, COL_SEO_DESKTOP, COL_A11Y_DESKTOP, COL_BP_DESKTOP],
    ];

    foreach ($rows as $row) {
        foreach ($columns[$mode] as $col) {
            if (isset($row[$col]) && $row[$col] !== null && $row[$col] !== '') {
                return true;
            }
        }
    }

    return false;
}

function buildStats(array $rows): array {
    $stats = [
        'total'       => count($rows),
        'scanned'     => 0,
        'pass'        => 0,
        'fail'        => 0,
        'error'       => 0,
        'not_scanned' => 0,
        'avg_mobile'  => ['perf' => null, 'seo' => null, 'a11y' => null, 'bp' => null],
        'avg_desktop' => ['perf' => null, 'seo' => null, 'a11y' => null, 'bp' => null],
    ];

    $mobileSums   = ['perf' => 0, 'seo' => 0, 'a11y' => 0, 'bp' => 0];
    $desktopSums  = ['perf' => 0, 'seo' => 0, 'a11y' => 0, 'bp' => 0];
    $mobileCounts = ['perf' => 0, 'seo' => 0, 'a11y' => 0, 'bp' => 0];
    $desktopCounts= ['perf' => 0, 'seo' => 0, 'a11y' => 0, 'bp' => 0];

    foreach ($rows as $row) {
        if (!empty($row[COL_SCANNED_AT])) {
            $stats['scanned']++;
        }

        $status = $row[COL_STATUS] ?? '';
        if ($status === 'pass') {
            $stats['pass']++;
        } elseif ($status === 'fail') {
            $stats['fail']++;
        } elseif ($status === 'error') {
            $stats['error']++;
        }

        foreach ([
            'perf' => [COL_PERF_MOBILE, COL_PERF_DESKTOP],
            'seo'  => [COL_SEO_MOBILE, COL_SEO_DESKTOP],
            'a11y' => [COL_A11Y_MOBILE, COL_A11Y_DESKTOP],
            'bp'   => [COL_BP_MOBILE, COL_BP_DESKTOP],
        ] as $key => $cols) {
            if (isset($row[$cols[0]]) && $row[$cols[0]] !== null && $row[$cols[0]] !== '') {
                $mobileSums[$key] += (int)$row[$cols[0]];
                $mobileCounts[$key]++;
            }
            if (isset($row[$cols[1]]) && $row[$cols[1]] !== null && $row[$cols[1]] !== '') {
                $desktopSums[$key] += (int)$row[$cols[1]];
                $desktopCounts[$key]++;
            }
        }
    }

    $stats['not_scanned'] = $stats['total'] - $stats['scanned'];

    foreach (['perf', 'seo', 'a11y', 'bp'] as $key) {
        if ($mobileCounts[$key] > 0) {
            $stats['avg_mobile'][$key] = (int)round($mobileSums[$key] / $mobileCounts[$key]);
        }
        if ($desktopCounts[$key] > 0) {
            $stats['avg_desktop'][$key] = (int)round($desktopSums[$key] / $desktopCounts[$key]);
        }
    }

    return $stats;
}

function prepareRow(array $row): array {
    $status = $row[COL_STATUS] ?? '';

    return [
        'sid'              => (int)($row['sid'] ?? 0),
        'domain'           => $row['domain'] ?? '',
        'status'           => $status,
        'scannedAt'        => $row[COL_SCANNED_AT] ?? '',
        'perf_mobile'      => normalizeScore($row[COL_PERF_MOBILE] ?? null),
        'seo_mobile'       => normalizeScore($row[COL_SEO_MOBILE] ?? null),
        'a11y_mobile'      => normalizeScore($row[COL_A11Y_MOBILE] ?? null),
        'bp_mobile'        => normalizeScore($row[COL_BP_MOBILE] ?? null),
        'perf_desktop'     => normalizeScore($row[COL_PERF_DESKTOP] ?? null),
        'seo_desktop'      => normalizeScore($row[COL_SEO_DESKTOP] ?? null),
        'a11y_desktop'     => normalizeScore($row[COL_A11Y_DESKTOP] ?? null),
        'bp_desktop'       => normalizeScore($row[COL_BP_DESKTOP] ?? null),
        'statusBadgeClass' => match ($status) {
            'pass' => 'bp',
            'fail' => 'bf',
            default => 'be',
        },
    ];
}

function normalizeScore($value): ?int {
    if ($value === null || $value === '') {
        return null;
    }
    return (int)$value;
}

function formatScore($value): string {
    return ($value === null || $value === '') ? '—' : (string)(int)$value;
}

function scoreCellClass($value): string {
    if ($value === null || $value === '') {
        return 'score-na';
    }
    $value = (int)$value;
    if ($value >= 90) {
        return 'score-good';
    }
    if ($value >= LIGHTHOUSE_FAIL_THRESHOLD) {
        return 'score-mid';
    }
    return 'score-bad';
}

function scoreNumberClass($value): string {
    if ($value === null || $value === '') {
        return 'cn-grey';
    }
    $value = (int)$value;
    if ($value >= 90) {
        return 'cn-good';
    }
    if ($value >= LIGHTHOUSE_FAIL_THRESHOLD) {
        return 'cn-mid';
    }
    return 'cn-bad';
}
