<?php
declare(strict_types=1);

/** Move only this nonce's private roots/barrier to a NEW 0700 archive. Never delete. */
function raceArchiveNoCover(string $journalPath, array $journal): array
{
    $lane = (string)($journal['lane'] ?? '');
    $marker = (string)($journal['marker'] ?? '');
    if (!in_array($lane, ['A', 'B', 'C'], true)
        || preg_match('/^CDXEMRACE[A-F0-9]{12}$/D', $marker) !== 1) {
        throw new RuntimeException('Archive identity invalid');
    }
    $nonce = strtolower(substr($marker, strlen('CDXEMRACE')));
    $barrier = '/tmp/cdx-em-race-barrier-' . $nonce;
    $archive = (string)($journal['archive_path'] ?? '');
    if ($archive !== ''
        && $journalPath === $archive . '/barrier/recovery.json') {
        if (!preg_match('~^/tmp/cdx-em-race-archive-'
                . preg_quote($nonce, '~') . '-[a-f0-9]{6}$~D', $archive)
            || is_link($archive) || realpath($archive) !== $archive
            || !is_dir($archive . '/barrier')
            || is_link($archive . '/barrier')) {
            throw new RuntimeException('Moved barrier archive path unsafe');
        }
        foreach ([1, 2] as $side) {
            $source = '/tmp/cdx-em-race-' . strtolower($lane)
                . '-' . $nonce . '-' . $side;
            if (file_exists($source)) {
                throw new RuntimeException('Archived barrier but active root remains');
            }
            $destination = $archive . '/worker' . $side;
            if (!is_dir($destination)
                && ($journal['worker_launch'][$side] ?? null) !== 'not_started') {
                throw new RuntimeException('Archived worker root missing');
            }
        }
        $journal['phase'] = 'archived';
        $text = json_encode($journal, JSON_UNESCAPED_SLASHES);
        if (!is_string($text) || file_put_contents($journalPath, $text, LOCK_EX) === false
            || !chmod($journalPath, 0600)) {
            throw new RuntimeException('Moved archive journal finalization failed');
        }
        return ['archive' => $archive, 'journal' => $journalPath,
            'worker1_archived' => is_dir($archive . '/worker1'),
            'worker2_archived' => is_dir($archive . '/worker2')];
    }
    if ($journalPath !== $barrier . '/recovery.json'
        || ($journal['barrier_dir'] ?? null) !== $barrier
        || !is_dir($barrier) || is_link($barrier)
        || realpath($barrier) !== $barrier) {
        throw new RuntimeException('Original private barrier not proven');
    }
    if ($archive === '') {
        $archive = '/tmp/cdx-em-race-archive-' . $nonce . '-'
            . strtolower(bin2hex(random_bytes(3)));
        if (file_exists($archive) || !mkdir($archive, 0700)
            || !chmod($archive, 0700)) {
            throw new RuntimeException('No-cover archive creation failed');
        }
        $journal['archive_path'] = $archive;
        $journal['phase'] = 'archive_started';
        $text = json_encode($journal, JSON_UNESCAPED_SLASHES);
        if (!is_string($text) || file_put_contents($journalPath, $text, LOCK_EX) === false
            || !chmod($journalPath, 0600)) {
            throw new RuntimeException('Archive plan journal not durable');
        }
    } elseif (!preg_match('~^/tmp/cdx-em-race-archive-'
        . preg_quote($nonce, '~') . '-[a-f0-9]{6}$~D', $archive)
        || is_link($archive) || realpath($archive) !== $archive
        || (((int)fileperms($archive) & 0077) !== 0)) {
        throw new RuntimeException('Prior archive path unsafe');
    }
    foreach ([1, 2] as $side) {
        $source = '/tmp/cdx-em-race-' . strtolower($lane)
            . '-' . $nonce . '-' . $side;
        if (($journal['worker_roots'][$side] ?? null) !== $source) {
            throw new RuntimeException('Worker root archive target drift');
        }
        $destination = $archive . '/worker' . $side;
        if (is_dir($source) && !is_link($source)) {
            if (file_exists($destination) || !rename($source, $destination)) {
                throw new RuntimeException('No-cover worker archive rename failed');
            }
        } elseif (file_exists($source)) {
            throw new RuntimeException('Worker root became symlink/file');
        } elseif (file_exists($destination)) {
            // Resume after earlier worker rename, never overwrite destination.
            if (!is_dir($destination) || is_link($destination)) {
                throw new RuntimeException('Archived worker root unsafe');
            }
        } elseif (($journal['worker_launch'][$side] ?? null) !== 'not_started') {
            throw new RuntimeException('Missing worker root after launch attempt');
        }
        $journal['archived_roots'][$side] = is_dir($destination);
        $text = json_encode($journal, JSON_UNESCAPED_SLASHES);
        if (!is_string($text) || file_put_contents($journalPath, $text, LOCK_EX) === false
            || !chmod($journalPath, 0600)) {
            throw new RuntimeException('Archive progress journal not durable');
        }
    }
    $destinationBarrier = $archive . '/barrier';
    if (file_exists($destinationBarrier)
        || !rename($barrier, $destinationBarrier)) {
        throw new RuntimeException('No-cover barrier archive rename failed');
    }
    $journal['phase'] = 'archived';
    $newJournal = $destinationBarrier . '/recovery.json';
    $text = json_encode($journal, JSON_UNESCAPED_SLASHES);
    if (!is_string($text) || file_put_contents($newJournal, $text, LOCK_EX) === false
        || !chmod($newJournal, 0600)) {
        throw new RuntimeException('Archived recovery journal not durable');
    }
    return ['archive' => $archive, 'journal' => $newJournal,
        'worker1_archived' => (bool)($journal['archived_roots'][1] ?? false),
        'worker2_archived' => (bool)($journal['archived_roots'][2] ?? false)];
}
