<?php
/**
 * Met à jour les champs `download.sizeBytes` et `download.sha256` de versions.json
 * en lisant les ZIPs présents dans /builds/. Le nom local du ZIP est dérivé du
 * champ `download.url` (basename de l'URL), donc tu peux nommer ton fichier comme
 * tu veux tant que le manifest pointe vers le bon nom.
 *
 * Usage (à exécuter via SSH OVH dans www/PS_Launcher/) :
 *   php tools/sign-manifest.php
 *
 * (v0.4) Ajoutera la signature Ed25519 globale du manifest.
 */
declare(strict_types=1);

$root = dirname(__DIR__);
$manifestPath = "$root/manifest/versions.json";
$buildsDir    = "$root/builds";

if (!is_file($manifestPath)) {
    fwrite(STDERR, "Manifest not found: $manifestPath\n");
    exit(1);
}

$manifest = json_decode(file_get_contents($manifestPath), true, 512, JSON_THROW_ON_ERROR);

$updated = 0;
$hashedVersions = [];
foreach ($manifest['versions'] as &$v) {
    $version = $v['version'] ?? '?';
    $url     = $v['download']['url'] ?? '';
    if ($url === '') {
        echo "  [skip] $version : pas d'URL dans le manifest\n";
        continue;
    }

    $filename = basename(parse_url($url, PHP_URL_PATH) ?: '');
    $zip = "$buildsDir/$filename";

    if (!is_file($zip)) {
        // Fallback : si le fichier n'existe pas exactement avec le nom de l'URL,
        // on tente une recherche tolérante par version (espaces / casse / séparateurs).
        $candidates = glob("$buildsDir/*{$version}*.zip", GLOB_NOSORT) ?: [];
        $candidates = array_values(array_filter($candidates, 'is_file'));
        if (count($candidates) === 1) {
            $zip = $candidates[0];
            echo "  [info] $version : URL pointait vers '{$filename}', utilisé '" . basename($zip) . "' à la place\n";
        } else {
            echo "  [skip] $version : ZIP introuvable pour $url\n";
            if (count($candidates) > 1) {
                echo "         Plusieurs candidats : " . implode(', ', array_map('basename', $candidates)) . "\n";
            }
            continue;
        }
    }

    $size = filesize($zip);
    echo "  [hash] $version : " . basename($zip) . " ($size octets)...";
    $sha = hash_file('sha256', $zip);
    echo " sha256={$sha}\n";

    $v['download']['sizeBytes'] = $size;
    $v['download']['sha256']    = $sha;
    $updated++;
    $hashedVersions[] = $version;
}
unset($v);

// Met à jour automatiquement le champ `latest` avec la plus haute version
// effectivement uploadée (celle pour laquelle on a calculé un hash).
if (!empty($hashedVersions)) {
    usort($hashedVersions, function ($a, $b) {
        return version_compare($a, $b);
    });
    $newLatest = end($hashedVersions);
    if (($manifest['latest'] ?? null) !== $newLatest) {
        echo "  [latest] {$manifest['latest']} -> {$newLatest}\n";
        $manifest['latest'] = $newLatest;
    }
}

// (v0.4) Signature Ed25519 du manifest
$configPath = dirname(__DIR__) . '/api/config.php';
if (is_file($configPath)) {
    require_once dirname(__DIR__) . '/api/lib/Crypto.php';
    $config = require $configPath;
    $sk = $config['ed25519']['private_key_hex'] ?? '';
    if ($sk !== '' && strlen($sk) === 128) {
        // Retire signature précédente, encode canonical, signe, ré-injecte
        $manifest['signature'] = null;
        $payload = \PSLauncher\Crypto::canonicalJson($manifest);
        $manifest['signature'] = \PSLauncher\Crypto::signEd25519($payload, $sk);
        echo "  [sign] manifest signed (Ed25519)\n";
    } else {
        echo "  [warn] ed25519.private_key_hex non configuré, manifest non signé\n";
    }
} else {
    echo "  [warn] config.php absent, manifest non signé\n";
}

file_put_contents(
    $manifestPath,
    json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"
);
echo "Manifest mis à jour ({$updated} version(s)) : $manifestPath\n";
