<?php

use App\Models\Host;
use App\Support\HostEnrolment;
use Illuminate\Testing\TestResponse;

/**
 * Das Archiv ist der einzige Weg, auf dem das Skript auf eine nackte Maschine
 * kommt. Was hier schiefgeht, merkt man erst im Rettungssystem eines Servers,
 * der schon bestellt ist.
 */
beforeEach(function () {
    fakeServices();
    $this->code = HostEnrolment::issue(Host::factory()->create());
});

function fetchArchive(): TestResponse
{
    return test()->get('http://files.clupilot.test/bootstrap.tar.gz?code='.test()->code);
}

it('serves the bootstrap script as an archive', function () {
    $response = fetchArchive();

    $response->assertOk();
    expect($response->headers->get('Content-Type'))->toBe('application/gzip');
});

/**
 * Der oberste Eintrag MUSS `bootstrap/` heißen. Die kopierte Zeile packt mit
 * `tar xz -C /opt/clupilot` aus, und das Skript sucht sich selbst unter
 * `/opt/clupilot/bootstrap` — ein anderer Name landet daneben, und der Fehler
 * zeigt sich als „lib/report.sh nicht gefunden" auf einer Maschine, an die man
 * nur über die Anbieterkonsole kommt.
 */
it('unpacks to bootstrap/ with the script and its library', function () {
    fetchArchive()->assertOk();

    $listing = shell_exec('tar tzf '.escapeshellarg(storage_path('app/bootstrap.tar.gz')));

    expect($listing)
        ->toContain('bootstrap/clupilot-bootstrap.sh')
        ->toContain('bootstrap/lib/report.sh')
        ->toContain('bootstrap/lib/proxmox.sh')
        ->toContain('bootstrap/lib/network.sh')
        ->toContain('bootstrap/lib/bridge.sh')
        ->toContain('bootstrap/lib/bridge-run.sh')
        ->toContain('bootstrap/lib/traefik.sh')
        ->toContain('bootstrap/lib/template.sh')
        ->toContain('bootstrap/lib/register.sh')
        ->toContain('bootstrap/assets/docker-compose.yml');
});

/**
 * Es darf nichts Vertrauliches darin stehen. Alle Geheimnisse reisen in der
 * Befehlszeile mit, die der Adminbereich genau einmal zeigt.
 */
it('carries no secrets', function () {
    fetchArchive()->assertOk();

    $dir = sys_get_temp_dir().'/bootstrap-pruefung-'.bin2hex(random_bytes(4));
    mkdir($dir);
    shell_exec('tar xzf '.escapeshellarg(storage_path('app/bootstrap.tar.gz')).' -C '.escapeshellarg($dir));

    $content = '';
    foreach (glob($dir.'/bootstrap/{,lib/,assets/}*', GLOB_BRACE) as $file) {
        if (is_file($file)) {
            $content .= file_get_contents($file);
        }
    }

    expect($content)->not->toBeEmpty()
        ->and($content)->not->toContain(config('app.key'))
        ->and($content)->not->toContain((string) env('SECRETS_KEY'));

    shell_exec('rm -rf '.escapeshellarg($dir));
});

/**
 * Ein Archiv, das einmal gebaut wurde und danach liegen bleibt, ist die Fassung
 * von dem Tag, an dem jemand zuletzt daran gedacht hat.
 */
it('rebuilds itself when the script changes', function () {
    fetchArchive()->assertOk();
    $first = filemtime(storage_path('app/bootstrap.tar.gz'));

    // Eine Sekunde zurück, damit die Änderung sichtbar später liegt.
    touch(storage_path('app/bootstrap.tar.gz'), $first - 10);
    touch(base_path('deploy/bootstrap/clupilot-bootstrap.sh'));

    fetchArchive()->assertOk();

    expect(filemtime(storage_path('app/bootstrap.tar.gz')))->toBeGreaterThan($first - 10);
});
