<?php

declare(strict_types=1);

/**
 * Release guard: every asset the admin links to must exist AND sit somewhere a core update
 * actually delivers.
 *
 * This is the guard 1.1.23 needed and did not have. A core update replaces only the paths
 * in UpdateManager::CORE_MANAGED_PATHS — and, crucially, it does so using the UpdateManager
 * ALREADY INSTALLED, i.e. the previous version's copy of that list. So a new directory added
 * to the list only takes effect for sites updating FROM that version onwards; every site on
 * an older release gets nothing. 1.1.23 shipped its stylesheet in public/assets/admin, which
 * no released updater has ever managed, and every updated site rendered an unstyled admin.
 *
 * Hence the rule enforced here: admin assets live under templates/admin/, which has been a
 * managed path in every release, and is reachable on disk through the public/templates
 * symlink. Both the managed list and the referenced files are derived, never restated.
 *
 * Run from the repo root:  php bin/check-shipped-assets.php
 */

$root = dirname(__DIR__);

 
$umSrc = (string) file_get_contents($root . '/src/Core/UpdateManager.php');
if (!preg_match('/CORE_MANAGED_PATHS\s*=\s*\[(.*?)\];/s', $umSrc, $m)) {
    fwrite(STDERR, "SHIPPED_ASSETS_FAIL: could not read CORE_MANAGED_PATHS out of UpdateManager.php\n");
    exit(1);
}
preg_match_all("/'([^']+)'/", $m[1], $pm);
$managed = $pm[1] ?? [];
if (count($managed) < 5) {
    fwrite(STDERR, "SHIPPED_ASSETS_FAIL: only " . count($managed) . " managed paths parsed — the constant's shape changed\n");
    exit(1);
}

 
$aaSrc = (string) file_get_contents($root . '/src/Core/AdminAssets.php');
if (!preg_match("/SOURCE_DIR\s*=\s*'([^']+)'/", $aaSrc, $sm)) {
    fwrite(STDERR, "SHIPPED_ASSETS_FAIL: could not read AdminAssets::SOURCE_DIR\n");
    exit(1);
}
$sourceDir = trim($sm[1], '/');

 
$covered = false;
foreach ($managed as $mp) {
    if ($sourceDir === $mp || str_starts_with($sourceDir . '/', rtrim($mp, '/') . '/')) {
        $covered = true;
        break;
    }
}
if (!$covered) {
    fwrite(STDERR, "SHIPPED_ASSETS_FAIL: admin assets live in " . $sourceDir . ", which no core update delivers.\n");
    fwrite(STDERR, "  Managed paths: " . implode(', ', $managed) . "\n");
    fwrite(STDERR, "  Adding it to CORE_MANAGED_PATHS is NOT enough — updates run the installed\n");
    fwrite(STDERR, "  (older) UpdateManager, so existing sites would still receive nothing.\n");
    exit(1);
}

 
$files = [];
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root . '/templates', FilesystemIterator::SKIP_DOTS));
foreach ($it as $f) {
    if ($f->isFile() && str_ends_with($f->getFilename(), '.php')) {
        $files[] = $f->getPathname();
    }
}

$refs = [];
foreach ($files as $path) {
    $src = (string) file_get_contents($path);
    if (preg_match_all("/AdminAssets::url\(\s*'([^']+)'\s*\)/", $src, $mm)) {
        foreach ($mm[1] as $rel) {
            $refs[$rel][] = str_replace($root . '/', '', $path);
        }
    }
     
    if (preg_match_all('~(?:src|href)="(/assets/admin/[^"?\s]+)~', $src, $mm2)) {
        foreach ($mm2[1] as $u) {
            $refs['RAW:' . $u][] = str_replace($root . '/', '', $path);
        }
    }
}

$problems = [];
foreach ($refs as $rel => $where) {
    if (str_starts_with($rel, 'RAW:')) {
        $problems[] = 'hard-coded ' . substr($rel, 4) . ' in ' . implode(', ', array_unique($where))
            . ' — use AdminAssets::url() so the fallback path still works when the mirror is unwritable';
        continue;
    }
    if (!is_file($root . '/' . $sourceDir . '/' . $rel)) {
        $problems[] = 'referenced but missing: ' . $sourceDir . '/' . $rel
            . '   (from ' . implode(', ', array_unique($where)) . ')';
    }
}

 
$css = $root . '/' . $sourceDir . '/flag-icons/flag-icons.css';
if (is_file($css) && preg_match_all('/url\(([^)]+)\)/', (string) file_get_contents($css), $um2)) {
    foreach (array_unique($um2[1]) as $u) {
        $u = trim($u, "'\" ");
        if (str_starts_with($u, 'data:') || str_starts_with($u, 'http')) {
            continue;
        }
        if (!is_file(dirname($css) . '/' . $u)) {
            $problems[] = 'flag-icons.css points at a missing file: ' . $u;
        }
    }
}

if ($problems) {
    fwrite(STDERR, "SHIPPED_ASSETS_FAIL\n");
    foreach ($problems as $p) {
        fwrite(STDERR, '  ' . $p . "\n");
    }
    exit(1);
}

fwrite(STDOUT, "SHIPPED_ASSETS_OK (" . count($refs) . " admin asset references, all present under "
    . $sourceDir . ", which core updates deliver)\n");
exit(0);
