<?php

// Wersja pliku: 0.0.15
declare(strict_types=1);

@ini_set('display_errors', '0');
@ini_set('display_startup_errors', '0');
@ini_set('html_errors', '0');
@ini_set('log_errors', '1');
header_remove('X-Powered-By');

const TE8_BOOTSTRAP_VERSION = null;
const TE8_BOOTSTRAP_RELEASE = '1.0.12';
const TE8_BOOTSTRAP_START_MODE = 'public-one-click-v1';
const TE8_INSTALLER_PRODUCT = 'install-system-te8';
const TE8_INSTALLER_NAME = 'System TE8';
const TE8_INSTALLER_DIRECTORY = 'install_system_te8';
const TE8_INSTALLER_HANDOFF_MODE = 'cookie-v1';
const TE8_PUBLIC_LATEST_URL = 'https://update.te8.pl/api/latest.php';
const TE8_PUBLIC_DOWNLOAD_URL = 'https://update.te8.pl/api/download.php';
const TE8_RELEASE_KEY_ID = 'te8-ed25519-b64e127719e2c66c';
const TE8_RELEASE_PUBLIC_KEY = 'deHHEB7unw9nxQRL38AY5DNdubx1cVg2nE7lIMc0QBQ=';
const TE8_METADATA_MAX_BYTES = 1048576;
const TE8_INSTALLER_ZIP_MAX_BYTES = 67108864;
const TE8_INSTALLER_ZIP_MAX_ENTRIES = 2048;
const TE8_INSTALLER_ZIP_MAX_FILE_BYTES = 67108864;
const TE8_INSTALLER_ZIP_MAX_UNCOMPRESSED_BYTES = 268435456;
const TE8_INSTALLER_ZIP_MAX_COMPRESSION_RATIO = 200;

bootstrapSecurityHeaders();
$locale = bootstrapLocale();
$error = null;
$bootstrapReady = false;
$bootstrapConsumed = false;
$selectedInstallerVersion = null;
$handoff = null;
$launchLock = null;

try {
    $selectedInstallerVersion = requestedInstallerVersion();
    bootstrapInstallerHandoffMode();
    if (bootstrapHttpsReady()) {
        bootstrapStartSession();
        $bootstrapConsumed = bootstrapLaunchConsumed();
        $bootstrapReady = true;
    }
} catch (Throwable $exception) {
    error_log('[TE8 install bootstrap] ' . $exception::class . ': ' . $exception->getMessage());
    $error = bootstrapText(
        'Bootstrap nie może uruchomić bezpiecznej sesji albo ma nieprawidłową konfigurację. Sprawdź konfigurację PHP i pliku instalacyjnego.',
        'The bootstrap cannot start a secure session or has an invalid configuration. Check PHP and installer file configuration.',
        $locale
    );
}

if (bootstrapScalar($_SERVER['REQUEST_METHOD'] ?? null, 'GET') === 'POST') {
    try {
        if (!$bootstrapReady) {
            throw new RuntimeException('Bootstrap nie jest gotowy do bezpiecznego uruchomienia.');
        }
        bootstrapRequireHttps();
        $handoffMode = bootstrapInstallerHandoffMode();
        bootstrapVerifyStartRequest();
        $launchLock = bootstrapAcquireLaunchLock();
        bootstrapAssertLaunchAvailable();
        $installation = runBootstrap();
        if ($handoffMode === 'cookie-v1') {
            $handoff = bootstrapCreateInstallerHandoff($installation, $locale);
            bootstrapSetInstallerHandoffCookie($handoff);
        }
        bootstrapMarkLaunchConsumed($installation);
        $bootstrapConsumed = true;
        bootstrapReleaseLaunchLock($launchLock);
        $launchLock = null;
        scheduleSelfDelete(__FILE__);
        header('Location: ' . (string) $installation['url'], true, 303);
        exit;
    } catch (Throwable $exception) {
        if (is_resource($launchLock)) {
            bootstrapReleaseLaunchLock($launchLock);
            $launchLock = null;
        }
        if (is_array($handoff)) {
            bootstrapDiscardInstallerHandoff($handoff);
            $handoff = null;
        }
        error_log('[TE8 install bootstrap] ' . $exception::class . ': ' . $exception->getMessage());
        $error = bootstrapText(
            'Nie udało się bezpiecznie pobrać albo zweryfikować instalatora. Sprawdź konfigurację serwera i spróbuj ponownie.',
            'The installer could not be downloaded or verified safely. Check the server configuration and try again.',
            $locale
        );
    }
}

renderPage($error, $locale, $selectedInstallerVersion, $bootstrapReady, $bootstrapConsumed);

/** @return array{url: string, version: string, target_path: string} */
function runBootstrap(): array
{
    if (!class_exists(ZipArchive::class)) {
        throw new RuntimeException('Na serwerze PHP brakuje rozszerzenia ZipArchive.');
    }

    $workRoot = dirname(__DIR__) . DIRECTORY_SEPARATOR . '.te8-bootstrap-runtime';
    ensureBootstrapRuntimeDirectory($workRoot);
    $lockFile = $workRoot . DIRECTORY_SEPARATOR . 'operation.lock';
    if (is_link($lockFile)) {
        throw new RuntimeException('Blokada bootstrapu nie moze byc dowiazaniem symbolicznym.');
    }
    $lock = @fopen($lockFile, 'c');
    if (!is_resource($lock)) {
        throw new RuntimeException('Nie udalo sie utworzyc blokady bootstrapu.');
    }
    if (!@chmod($lockFile, 0600)) {
        fclose($lock);
        throw new RuntimeException('Nie udalo sie zabezpieczyc blokady bootstrapu.');
    }
    clearstatcache(true, $lockFile);
    $lockPermissions = @fileperms($lockFile);
    if (is_link($lockFile) || !is_file($lockFile)
        || (DIRECTORY_SEPARATOR === '/' && (!is_int($lockPermissions) || ($lockPermissions & 0777) !== 0600))
    ) {
        fclose($lock);
        throw new RuntimeException('Blokada bootstrapu ma nieprawidlowe uprawnienia.');
    }
    if (!flock($lock, LOCK_EX | LOCK_NB)) {
        fclose($lock);
        throw new RuntimeException('Inne uruchomienie bootstrapu jest juz w toku.');
    }

    try {
        $metadataPayload = [
            'product' => TE8_INSTALLER_PRODUCT,
            'package_kind' => 'installer',
        ];
        $requestedVersion = requestedInstallerVersion();
        if ($requestedVersion !== null) {
            $metadataPayload['version'] = $requestedVersion;
        }

        $latest = requestJson(TE8_PUBLIC_LATEST_URL, $metadataPayload, 30);
        if (empty($latest['ok'])) {
            throw new RuntimeException('Update TE8 nie zwrocil aktywnego instalatora: ' . (string) ($latest['error'] ?? 'brak szczegolow'));
        }
        if ((string) ($latest['package_kind'] ?? '') !== 'installer') {
            throw new RuntimeException('Serwer update zwrocil nieprawidlowy typ paczki.');
        }

        $version = trim((string) ($latest['version'] ?? ''));
        $checksum = strtolower(trim((string) ($latest['checksum_sha256'] ?? '')));
        if ($version === '') {
            throw new RuntimeException('Serwer update nie zwrocil wersji instalatora.');
        }
        if ($requestedVersion !== null && $version !== $requestedVersion) {
            throw new RuntimeException('Serwer update zwrocil inna wersje instalatora niz wskazana w bootstrapie.');
        }
        verifyInstallerMetadataSignature($latest, $version, $checksum);

        $binary = requestRaw(TE8_PUBLIC_DOWNLOAD_URL, [
            'product' => TE8_INSTALLER_PRODUCT,
            'package_kind' => 'installer',
            'version' => $version,
        ], 60);
        if (!hash_equals($checksum, hash('sha256', $binary))) {
            throw new RuntimeException('Suma SHA-256 pobranego instalatora jest niezgodna.');
        }

        $runId = gmdate('YmdHis') . '-' . bin2hex(random_bytes(8));
        $zipFile = $workRoot . DIRECTORY_SEPARATOR . TE8_INSTALLER_PRODUCT . '-' . $version . '-' . $runId . '.zip';
        $extractPath = $workRoot . DIRECTORY_SEPARATOR . 'extract-' . $runId;
        $preparedPath = $workRoot . DIRECTORY_SEPARATOR . 'prepared-' . $runId;
        if (file_put_contents($zipFile, $binary, LOCK_EX) === false) {
            throw new RuntimeException('Nie udalo sie zapisac pobranego ZIP instalatora.');
        }

        try {
            safeExtractZip($zipFile, $extractPath);
            $packageRoot = resolveInstallerPackageRoot($extractPath);
            validateInstallerPackageRoot($packageRoot, $version);
            copyTree($packageRoot, $preparedPath);
            installPreparedInstaller(
                $preparedPath,
                __DIR__ . DIRECTORY_SEPARATOR . TE8_INSTALLER_DIRECTORY,
                $workRoot,
                $runId
            );
        } finally {
            bootstrapCleanupPath($preparedPath);
            bootstrapCleanupPath($extractPath);
            bootstrapCleanupPath($zipFile);
        }

        $targetPath = __DIR__ . DIRECTORY_SEPARATOR . TE8_INSTALLER_DIRECTORY;
        $resolvedTarget = realpath($targetPath);
        if (!is_string($resolvedTarget) || !is_dir($resolvedTarget) || is_link($resolvedTarget)) {
            throw new RuntimeException('Opublikowany instalator ma nieprawidlowa sciezke.');
        }
        return [
            'url' => './' . TE8_INSTALLER_DIRECTORY . '/',
            'version' => $version,
            'target_path' => $resolvedTarget,
        ];
    } finally {
        flock($lock, LOCK_UN);
        fclose($lock);
        clearstatcache(true, $lockFile);
        if (is_file($lockFile) && !is_link($lockFile)) {
            @unlink($lockFile);
        }
        @rmdir($workRoot);
    }
}

/** @param array<string, mixed> $metadata */
function verifyInstallerMetadataSignature(array $metadata, string $version, string $checksum): void
{
    $signature = $metadata['signature'] ?? null;
    $zipFilename = trim((string) ($metadata['zip_filename'] ?? ''));
    if (!is_array($signature)
        || strtolower(trim((string) ($signature['algorithm'] ?? ''))) !== 'ed25519'
        || trim((string) ($signature['payload_version'] ?? '')) !== 'te8-release/v1'
        || !hash_equals(TE8_RELEASE_KEY_ID, trim((string) ($signature['key_id'] ?? '')))
        || preg_match('/^[a-zA-Z0-9][a-zA-Z0-9._+~-]{0,39}$/', $version) !== 1
        || preg_match('/^[a-f0-9]{64}$/', $checksum) !== 1
        || $zipFilename !== basename($zipFilename)
        || preg_match('/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}\.zip$/i', $zipFilename) !== 1) {
        throw new RuntimeException('Metadane instalatora nie zawieraja prawidlowego podpisu cyfrowego.');
    }

    $publicKey = base64_decode(TE8_RELEASE_PUBLIC_KEY, true);
    $detached = base64_decode(trim((string) ($signature['signature_base64'] ?? '')), true);
    if (!is_string($publicKey) || strlen($publicKey) !== 32
        || !is_string($detached) || strlen($detached) !== 64
        || !hash_equals(TE8_RELEASE_KEY_ID, 'te8-ed25519-' . substr(hash('sha256', $publicKey), 0, 16))) {
        throw new RuntimeException('Podpis albo klucz publiczny instalatora ma nieprawidlowy format.');
    }

    $payload = implode("\n", [
        'TE8-RELEASE-SIGNATURE-V1',
        'product=' . TE8_INSTALLER_PRODUCT,
        'package_kind=installer',
        'version=' . $version,
        'zip_filename=' . $zipFilename,
        'sha256=' . $checksum,
        '',
    ]);
    if (!verifyEd25519Detached($detached, $payload, $publicKey)) {
        throw new RuntimeException('Podpis cyfrowy instalatora jest nieprawidlowy. Pobieranie zostalo zatrzymane.');
    }
}

function verifyEd25519Detached(string $signature, string $payload, string $publicKey): bool
{
    if (function_exists('sodium_crypto_sign_verify_detached')) {
        return sodium_crypto_sign_verify_detached($signature, $payload, $publicKey);
    }
    if (function_exists('openssl_verify') && function_exists('openssl_pkey_get_public')) {
        $der = hex2bin('302a300506032b6570032100') . $publicKey;
        $pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split(base64_encode($der), 64, "\n") . "-----END PUBLIC KEY-----\n";
        $key = @openssl_pkey_get_public($pem);
        if ($key !== false) {
            return @openssl_verify($payload, $signature, $key, 0) === 1;
        }
    }
    throw new RuntimeException('PHP nie ma obslugi Ed25519 przez Sodium ani OpenSSL.');
}

function requestedInstallerVersion(): ?string
{
    if (TE8_BOOTSTRAP_VERSION === null) {
        return null;
    }

    $version = trim((string) TE8_BOOTSTRAP_VERSION);
    if ($version === '') {
        return null;
    }

    if (preg_match('/^\d+\.\d+\.\d+$/', $version) !== 1) {
        throw new RuntimeException('TE8_BOOTSTRAP_VERSION musi byc null albo wersja w formacie x.x.x.');
    }

    return $version;
}

/**
 * @param array<string, scalar> $payload
 * @return array<string, mixed>
 */
function requestJson(string $url, array $payload, int $timeout): array
{
    $body = requestRaw($url, $payload, $timeout);
    $decoded = json_decode($body, true);

    if (!is_array($decoded)) {
        throw new RuntimeException('Serwer update zwrocil nieprawidlowa odpowiedz JSON.');
    }

    return $decoded;
}

/**
 * @param array<string, scalar> $payload
 */
function requestRaw(string $url, array $payload, int $timeout): string
{
    if (!filter_var($url, FILTER_VALIDATE_URL)
        || (!hash_equals(TE8_PUBLIC_LATEST_URL, $url) && !hash_equals(TE8_PUBLIC_DOWNLOAD_URL, $url))
        || strtolower((string) parse_url($url, PHP_URL_SCHEME)) !== 'https'
        || strtolower((string) parse_url($url, PHP_URL_HOST)) !== 'update.te8.pl'
        || parse_url($url, PHP_URL_USER) !== null
        || parse_url($url, PHP_URL_PASS) !== null
        || parse_url($url, PHP_URL_FRAGMENT) !== null
    ) {
        throw new RuntimeException('Nieprawidlowy adres API update.');
    }
    $maxResponseBytes = hash_equals(TE8_PUBLIC_DOWNLOAD_URL, $url)
        ? TE8_INSTALLER_ZIP_MAX_BYTES
        : TE8_METADATA_MAX_BYTES;

    $json = json_encode($payload, JSON_UNESCAPED_SLASHES);
    if (!is_string($json)) {
        throw new RuntimeException('Nie udalo sie przygotowac danych zapytania.');
    }

    if (function_exists('curl_init')) {
        $curl = curl_init($url);
        if ($curl === false) {
            throw new RuntimeException('Nie udalo sie uruchomic cURL.');
        }

        $responseBody = '';
        $overflow = false;
        $options = [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $json,
            CURLOPT_RETURNTRANSFER => false,
            CURLOPT_CONNECTTIMEOUT => $timeout,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_FOLLOWLOCATION => false,
            CURLOPT_MAXREDIRS => 0,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Accept: application/json, application/octet-stream',
            ],
            CURLOPT_WRITEFUNCTION => static function ($handle, string $chunk) use (&$responseBody, &$overflow, $maxResponseBytes): int {
                $length = strlen($chunk);
                if (strlen($responseBody) + $length > $maxResponseBytes) {
                    $overflow = true;
                    return 0;
                }
                $responseBody .= $chunk;
                return $length;
            },
        ];
        if (!@curl_setopt_array($curl, $options)) {
            curl_close($curl);
            throw new RuntimeException('Nie udalo sie ustawic bezpiecznych opcji cURL.');
        }

        $response = curl_exec($curl);
        $status = (int) curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
        $error = curl_error($curl);
        curl_close($curl);

        if ($response !== true || $overflow) {
            if ($overflow) {
                throw new RuntimeException('Odpowiedz update.te8.pl przekracza bezpieczny limit rozmiaru.');
            }
            throw new RuntimeException('Blad polaczenia z update.te8.pl: ' . ($error !== '' ? $error : 'brak odpowiedzi'));
        }

        if ($status !== 200) {
            throw new RuntimeException(formatUpdateHttpError($status, $responseBody, $url, $payload));
        }

        return $responseBody;
    }

    $context = stream_context_create([
        'http' => [
            'method' => 'POST',
            'header' => "Content-Type: application/json\r\nAccept: application/json, application/octet-stream\r\n",
            'content' => $json,
            'timeout' => $timeout,
            'ignore_errors' => true,
            'follow_location' => 0,
            'max_redirects' => 0,
            'protocol_version' => 1.1,
        ],
        'ssl' => [
            'verify_peer' => true,
            'verify_peer_name' => true,
        ],
    ]);

    $response = @file_get_contents($url, false, $context, 0, $maxResponseBytes + 1);
    if (!is_string($response)) {
        throw new RuntimeException('Nie udalo sie polaczyc z update.te8.pl. Wlacz cURL albo allow_url_fopen.');
    }
    if (strlen($response) > $maxResponseBytes) {
        throw new RuntimeException('Odpowiedz update.te8.pl przekracza bezpieczny limit rozmiaru.');
    }

    $status = responseStatus($http_response_header ?? []);
    if ($status !== 200) {
        throw new RuntimeException(formatUpdateHttpError($status, $response, $url, $payload));
    }

    return $response;
}

/**
 * @param array<string, scalar> $payload
 */
function formatUpdateHttpError(int $status, string $response, string $url, array $payload): string
{
    $decoded = json_decode($response, true);
    $serverError = is_array($decoded)
        ? trim((string) ($decoded['error'] ?? $decoded['message'] ?? ''))
        : trim(strip_tags($response));
    $path = (string) (parse_url($url, PHP_URL_PATH) ?: $url);
    $product = (string) ($payload['product'] ?? TE8_INSTALLER_PRODUCT);

    if ($status === 404) {
        return 'Nie znaleziono endpointu instalatora w update.te8.pl (HTTP 404). '
            . 'Najczestsza przyczyna: update.te8.pl nie ma jeszcze wdrozonego publicznego trybu pobierania instalatora. '
            . 'Wymagany endpoint: ' . $path . '. '
            . 'Produkt: ' . $product . '. '
            . 'Odpowiedz serwera: ' . ($serverError !== '' ? $serverError : 'brak szczegolow') . '.';
    }

    return 'Update TE8 odrzucil zapytanie HTTP ' . $status . '. '
        . 'Endpoint: ' . $path . '. '
        . 'Produkt: ' . $product . '. '
        . 'Odpowiedz serwera: ' . ($serverError !== '' ? substr($serverError, 0, 300) : 'brak szczegolow') . '.';
}

/**
 * @param list<string> $headers
 */
function responseStatus(array $headers): int
{
    $status = 0;
    foreach ($headers as $header) {
        if (preg_match('/^HTTP\/\S+\s+(\d{3})/', $header, $match) === 1) {
            $status = (int) $match[1];
        }
    }

    return $status;
}

function safeExtractZip(string $zipFile, string $extractPath): void
{
    ensureDirectory($extractPath);
    $zip = new ZipArchive();

    if ($zip->open($zipFile) !== true) {
        throw new RuntimeException('Nie udalo sie otworzyc ZIP instalatora.');
    }

    try {
        if ($zip->numFiles < 1 || $zip->numFiles > TE8_INSTALLER_ZIP_MAX_ENTRIES) {
            throw new RuntimeException('ZIP instalatora ma nieprawidlowa liczbe wpisow.');
        }
        $seen = [];
        $directories = [];
        $totalBytes = 0;
        for ($i = 0; $i < $zip->numFiles; $i++) {
            $stat = $zip->statIndex($i);
            if (!is_array($stat)) {
                throw new RuntimeException('Nie udalo sie odczytac wpisu ZIP instalatora.');
            }
            $name = (string) ($stat['name'] ?? '');
            $isDirectory = str_ends_with($name, '/');
            $relative = safeZipRelativePath($name);
            $key = strtolower($relative);
            if (isset($seen[$key])) {
                throw new RuntimeException('ZIP instalatora zawiera zduplikowana sciezke.');
            }
            $seen[$key] = $isDirectory ? 'directory' : 'file';

            $opsys = 0;
            $externalAttributes = 0;
            $mode = $zip->getExternalAttributesIndex($i, $opsys, $externalAttributes)
                ? (($externalAttributes >> 16) & 0170000)
                : 0;
            if ($mode === 0120000 || !in_array($mode, [0, 0040000, 0100000], true)
                || ($isDirectory && $mode === 0100000) || (!$isDirectory && $mode === 0040000)
                || (isset($stat['encryption_method']) && (int) $stat['encryption_method'] !== 0)
            ) {
                throw new RuntimeException('ZIP instalatora zawiera niedozwolony typ wpisu.');
            }

            $parts = explode('/', $relative);
            $prefix = '';
            for ($partIndex = 0; $partIndex < count($parts) - 1; $partIndex++) {
                $prefix = $prefix === '' ? $parts[$partIndex] : $prefix . '/' . $parts[$partIndex];
                $prefixKey = strtolower($prefix);
                if (($seen[$prefixKey] ?? null) === 'file') {
                    throw new RuntimeException('ZIP instalatora zawiera konflikt pliku i katalogu.');
                }
                $directories[$prefixKey] = true;
            }

            $target = $extractPath . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relative);
            if ($isDirectory) {
                if (($seen[$key] ?? null) === 'file') {
                    throw new RuntimeException('ZIP instalatora zawiera konflikt pliku i katalogu.');
                }
                $directories[$key] = true;
                ensureDirectory($target);
                continue;
            }
            if (isset($directories[$key])) {
                throw new RuntimeException('ZIP instalatora zawiera konflikt pliku i katalogu.');
            }

            $size = (int) ($stat['size'] ?? -1);
            $compressedSize = (int) ($stat['comp_size'] ?? -1);
            if ($size < 0 || $compressedSize < 0 || $size > TE8_INSTALLER_ZIP_MAX_FILE_BYTES
                || $totalBytes > TE8_INSTALLER_ZIP_MAX_UNCOMPRESSED_BYTES - $size
                || ($size > 0 && $compressedSize < 1)
                || ($size >= 1048576 && $size > $compressedSize * TE8_INSTALLER_ZIP_MAX_COMPRESSION_RATIO)
            ) {
                throw new RuntimeException('ZIP instalatora przekracza bezpieczne limity rozmiaru.');
            }
            $totalBytes += $size;
            ensureDirectory(dirname($target));
            if (file_exists($target) || is_link($target)) {
                throw new RuntimeException('ZIP instalatora probuje nadpisac istniejaca sciezke.');
            }
            $input = $zip->getStream($name);
            $output = @fopen($target, 'x+b');
            if (!is_resource($input) || !is_resource($output)) {
                if (is_resource($input)) {
                    fclose($input);
                }
                if (is_resource($output)) {
                    fclose($output);
                }
                throw new RuntimeException('Nie udalo sie zapisac pliku z ZIP instalatora.');
            }
            $writtenBytes = 0;
            try {
                while (!feof($input)) {
                    $chunk = fread($input, 65536);
                    if (!is_string($chunk)) {
                        throw new RuntimeException('Nie udalo sie odczytac pliku z ZIP instalatora.');
                    }
                    if ($chunk === '') {
                        throw new RuntimeException('Nie udalo sie odczytac calego pliku z ZIP instalatora.');
                    }
                    $writtenBytes += strlen($chunk);
                    if ($writtenBytes > $size || $writtenBytes > TE8_INSTALLER_ZIP_MAX_FILE_BYTES) {
                        throw new RuntimeException('Rozpakowany plik przekracza zadeklarowany rozmiar.');
                    }
                    $offset = 0;
                    while ($offset < strlen($chunk)) {
                        $written = fwrite($output, substr($chunk, $offset));
                        if (!is_int($written) || $written < 1) {
                            throw new RuntimeException('Nie udalo sie zapisac pliku z ZIP instalatora.');
                        }
                        $offset += $written;
                    }
                }
                if ($writtenBytes !== $size || !fflush($output)) {
                    throw new RuntimeException('Rozpakowany plik ma nieprawidlowy rozmiar.');
                }
            } finally {
                fclose($input);
                fclose($output);
            }
            @chmod($target, 0644);
        }
    } finally {
        $zip->close();
    }
}

function safeZipRelativePath(string $path): string
{
    if ($path === '' || strlen($path) > 1024 || str_contains($path, '\\')
        || str_starts_with($path, '/') || preg_match('/^[A-Za-z]:/', $path) === 1
        || preg_match('/[\x00-\x1F\x7F]/', $path) === 1
    ) {
        throw new RuntimeException('ZIP instalatora zawiera niebezpieczna sciezke.');
    }
    $normalized = str_ends_with($path, '/') ? substr($path, 0, -1) : $path;
    $parts = explode('/', $normalized);
    if ($normalized === '' || count($parts) > 64) {
        throw new RuntimeException('ZIP instalatora zawiera niebezpieczna sciezke.');
    }
    foreach ($parts as $part) {
        if ($part === '' || $part === '.' || $part === '..' || str_contains($part, ':') || strlen($part) > 255) {
            throw new RuntimeException('ZIP instalatora zawiera niebezpieczna sciezke.');
        }
    }
    return implode('/', $parts);
}

function resolveInstallerPackageRoot(string $extractPath): string
{
    $candidates = [$extractPath];
    $items = @scandir($extractPath) ?: [];

    foreach ($items as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }

        $path = $extractPath . DIRECTORY_SEPARATOR . $item;
        if (is_dir($path)) {
            $candidates[] = $path;
        }
    }

    $matches = [];
    foreach ($candidates as $candidate) {
        if (is_link($candidate) || !is_dir($candidate)) {
            continue;
        }
        foreach (installerPackageRequiredFiles() as $requiredFile) {
            $requiredPath = $candidate . DIRECTORY_SEPARATOR . $requiredFile;
            if (!is_file($requiredPath) || is_link($requiredPath)) {
                continue 2;
            }
        }
        $matches[] = $candidate;
    }
    if (count($matches) !== 1) {
        throw new RuntimeException('Pobrany ZIP nie zawiera jednoznacznego instalatora TE8.');
    }
    return $matches[0];
}

function validateInstallerPackageRoot(string $packageRoot, string $version): void
{
    if (!is_dir($packageRoot) || is_link($packageRoot)) {
        throw new RuntimeException('Katalog pobranego instalatora jest niepoprawny.');
    }
    foreach (installerPackageRequiredFiles() as $requiredFile) {
        $requiredPath = $packageRoot . DIRECTORY_SEPARATOR . $requiredFile;
        if (!is_file($requiredPath) || is_link($requiredPath)) {
            throw new RuntimeException('Pobrany instalator jest niekompletny.');
        }
    }
    try {
        $manifest = json_decode(
            readInstallerPackageText($packageRoot . DIRECTORY_SEPARATOR . 'te8-package.json', 65536),
            true,
            32,
            JSON_THROW_ON_ERROR
        );
    } catch (JsonException) {
        throw new RuntimeException('Manifest te8-package.json instalatora jest niepoprawny.');
    }
    if (!is_array($manifest) || array_is_list($manifest) || ($manifest['schema'] ?? null) !== 'te8-package/v1') {
        throw new RuntimeException('Manifest te8-package.json instalatora jest niepoprawny.');
    }

    $product = trim((string) ($manifest['product'] ?? $manifest['product_code'] ?? ''));
    $kind = trim((string) ($manifest['package_kind'] ?? ''));
    $manifestVersion = trim((string) ($manifest['version'] ?? ''));

    $fileVersion = trim(readInstallerPackageText($packageRoot . DIRECTORY_SEPARATOR . 'VERSION', 4096));
    $fileProduct = trim(readInstallerPackageText($packageRoot . DIRECTORY_SEPARATOR . 'PRODUKT', 4096));
    $fileKind = trim(readInstallerPackageText($packageRoot . DIRECTORY_SEPARATOR . 'PACKAGE_KIND', 4096));
    if ($product !== TE8_INSTALLER_PRODUCT || $kind !== 'installer' || $manifestVersion !== $version
        || $fileVersion !== $version || $fileProduct !== TE8_INSTALLER_PRODUCT || $fileKind !== 'installer'
    ) {
        throw new RuntimeException('Manifest pobranego instalatora nie zgadza sie z oczekiwana paczka.');
    }
    if (bootstrapInstallerHandoffMode() === 'cookie-v1') {
        $handoffMarker = $packageRoot . DIRECTORY_SEPARATOR . 'INSTALLER_HANDOFF';
        if (($manifest['bootstrap_handoff'] ?? null) !== 'te8-installer-handoff/v1'
            || trim(readInstallerPackageText($handoffMarker, 4096)) !== 'te8-installer-handoff/v1'
        ) {
            throw new RuntimeException('Instalator nie obsluguje bezpiecznego przekazania kontroli v1.');
        }
    }
}

/** @return list<string> */
function installerPackageRequiredFiles(): array
{
    return [
        '.htaccess', 'index.php', 'installer.php', 'InstallerService.php', 'InstallerAccessGate.php',
        'ReleaseSignatureVerifier.php', 'install.ps1', 'wizard.css', 'wizard.js',
        'legal/LP-04-LICENCJA-SYSTEM-TE8-EULA.html', 'license.txt', 'VERSION', 'PRODUKT',
        'PACKAGE_KIND', 'te8-package.json', 'INSTALLER_HANDOFF', 'README.md', 'RELEASE_NOTES.md',
        'STORE_INSTALLER.md',
    ];
}

function readInstallerPackageText(string $path, int $maxBytes): string
{
    clearstatcache(true, $path);
    $size = @filesize($path);
    if (is_link($path) || !is_file($path) || !is_int($size) || $size < 1 || $size > $maxBytes) {
        throw new RuntimeException('Plik tozsamosci pobranego instalatora jest nieprawidlowy.');
    }
    $contents = @file_get_contents($path);
    if (!is_string($contents) || strlen($contents) !== $size) {
        throw new RuntimeException('Nie mozna odczytac pliku tozsamosci pobranego instalatora.');
    }
    return $contents;
}

function assertSafeTargetDirectory(string $targetPath): void
{
    $base = realpath(__DIR__);
    $parent = realpath(dirname($targetPath));

    if (!is_string($base) || !is_string($parent) || $base !== $parent) {
        throw new RuntimeException('Docelowy katalog instalatora musi byc w tym samym webroot.');
    }
    if (is_link($targetPath)) {
        throw new RuntimeException('Docelowy katalog instalatora nie moze byc dowiazaniem symbolicznym.');
    }
    if (file_exists($targetPath) && !is_dir($targetPath)) {
        throw new RuntimeException('Docelowa sciezka instalatora nie jest katalogiem.');
    }
}

function installPreparedInstaller(string $preparedPath, string $targetPath, string $workRoot, string $runId): void
{
    assertSafeTargetDirectory($targetPath);
    if (!is_dir($preparedPath) || is_link($preparedPath)) {
        throw new RuntimeException('Przygotowany instalator ma nieprawidlowa postac.');
    }

    $backupPath = $workRoot . DIRECTORY_SEPARATOR . 'previous-' . $runId;
    $hadPrevious = is_dir($targetPath);
    if ($hadPrevious && !@rename($targetPath, $backupPath)) {
        throw new RuntimeException('Nie udalo sie bezpiecznie odsunac poprzedniego instalatora.');
    }

    try {
        if (!@rename($preparedPath, $targetPath)) {
            throw new RuntimeException('Nie udalo sie atomowo opublikowac instalatora.');
        }
    } catch (Throwable $exception) {
        if ($hadPrevious && !file_exists($targetPath) && !is_link($targetPath)
            && !@rename($backupPath, $targetPath)
        ) {
            throw new RuntimeException('Nie udalo sie przywrocic poprzedniego instalatora.', 0, $exception);
        }
        throw $exception;
    }

    if ($hadPrevious) {
        bootstrapCleanupPath($backupPath);
    }
}

function ensureBootstrapRuntimeDirectory(string $directory): void
{
    $parent = realpath(dirname($directory));
    if (!is_string($parent) || is_link($directory) || (file_exists($directory) && !is_dir($directory))) {
        throw new RuntimeException('Prywatny katalog roboczy bootstrapu jest niebezpieczny.');
    }
    if (!is_dir($directory) && !mkdir($directory, 0700, true) && !is_dir($directory)) {
        throw new RuntimeException('Nie mozna utworzyc prywatnego katalogu roboczego bootstrapu.');
    }
    $resolved = realpath($directory);
    if (!is_string($resolved) || dirname($resolved) !== $parent) {
        throw new RuntimeException('Prywatny katalog roboczy bootstrapu ma nieprawidlowa sciezke.');
    }
    if (DIRECTORY_SEPARATOR === '/') {
        if (!@chmod($directory, 0700)) {
            throw new RuntimeException('Nie mozna zabezpieczyc prywatnego katalogu roboczego bootstrapu.');
        }
        $permissions = @fileperms($directory);
        if (!is_int($permissions) || ($permissions & 0777) !== 0700) {
            throw new RuntimeException('Prywatny katalog roboczy bootstrapu ma nieprawidlowe uprawnienia.');
        }
    }
}

function ensureDirectory(string $directory): void
{
    if (is_link($directory)) {
        throw new RuntimeException('Katalog roboczy nie moze byc dowiazaniem symbolicznym.');
    }
    if (!is_dir($directory) && !mkdir($directory, 0775, true) && !is_dir($directory)) {
        throw new RuntimeException('Nie mozna utworzyc katalogu: ' . $directory);
    }
}

function copyTree(string $source, string $target): void
{
    ensureDirectory($target);
    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($source, FilesystemIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($items as $item) {
        $relative = substr($item->getPathname(), strlen($source) + 1);
        $destination = $target . DIRECTORY_SEPARATOR . $relative;

        if ($item->isLink()) {
            throw new RuntimeException('Pobrany instalator zawiera niedozwolone dowiazanie symboliczne.');
        }
        if ($item->isDir()) {
            ensureDirectory($destination);
            continue;
        }

        ensureDirectory(dirname($destination));
        if (!copy($item->getPathname(), $destination)) {
            throw new RuntimeException('Nie udalo sie skopiowac pliku instalatora.');
        }
    }
}

function removeTree(string $path): void
{
    if ($path === '' || (!file_exists($path) && !is_link($path))) {
        return;
    }

    if (is_file($path) || is_link($path)) {
        if (!unlink($path)) {
            throw new RuntimeException('Nie udalo sie usunac pliku roboczego bootstrapu.');
        }
        return;
    }

    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );

    foreach ($items as $item) {
        if ($item->isLink()) {
            if (!unlink($item->getPathname())) {
                throw new RuntimeException('Nie udalo sie usunac dowiazania z katalogu roboczego.');
            }
            continue;
        }
        if ($item->isDir()) {
            if (!rmdir($item->getPathname())) {
                throw new RuntimeException('Nie udalo sie usunac katalogu roboczego bootstrapu.');
            }
            continue;
        }

        if (!unlink($item->getPathname())) {
            throw new RuntimeException('Nie udalo sie usunac pliku z katalogu roboczego.');
        }
    }

    if (!rmdir($path)) {
        throw new RuntimeException('Nie udalo sie usunac katalogu roboczego bootstrapu.');
    }
}

function bootstrapCleanupPath(string $path): void
{
    try {
        removeTree($path);
    } catch (Throwable $exception) {
        error_log('[TE8 install bootstrap] Niepelne sprzatanie katalogu roboczego: ' . $exception->getMessage());
    }
}

function scheduleSelfDelete(string $file): void
{
    if (is_file($file) && !is_link($file) && @unlink($file)) {
        return;
    }
    register_shutdown_function(static function () use ($file): void {
        @unlink($file);
    });
}

function bootstrapSecurityHeaders(): void
{
    header_remove('X-Powered-By');
    header('X-Content-Type-Options: nosniff');
    header('X-Frame-Options: DENY');
    header('Referrer-Policy: no-referrer');
    header("Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; form-action 'self'; base-uri 'none'; frame-ancestors 'none'");
    header('Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()');
    header('Cache-Control: no-store, max-age=0');
    if (bootstrapHttpsReady()) {
        header('Strict-Transport-Security: max-age=31536000');
    }
}

function bootstrapHttpsReady(): bool
{
    $https = strtolower(trim(bootstrapScalar($_SERVER['HTTPS'] ?? null)));
    return in_array($https, ['on', '1'], true) || bootstrapScalar($_SERVER['SERVER_PORT'] ?? null) === '443';
}

function bootstrapRequireHttps(): void
{
    if (!bootstrapHttpsReady()) {
        throw new RuntimeException('Bootstrap instalatora wymaga bezposredniego polaczenia HTTPS.');
    }
}

function bootstrapStartSession(): void
{
    if (session_status() !== PHP_SESSION_NONE) {
        throw new RuntimeException('Sesja PHP zostala uruchomiona przed bootstrapem.');
    }
    bootstrapRequireSessionIni('session.use_strict_mode', true);
    bootstrapRequireSessionIni('session.use_cookies', true);
    bootstrapRequireSessionIni('session.use_only_cookies', true);
    bootstrapRequireSessionIni('session.use_trans_sid', false);
    if (session_name('TE8BOOTSTRAP') === false || !session_set_cookie_params([
        'lifetime' => 0,
        'path' => '/',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Strict',
    ])) {
        throw new RuntimeException('Nie udalo sie ustawic bezpiecznych parametrow sesji bootstrapu.');
    }
    $cookie = session_get_cookie_params();
    if (($cookie['secure'] ?? false) !== true
        || ($cookie['httponly'] ?? false) !== true
        || ($cookie['samesite'] ?? '') !== 'Strict'
        || ($cookie['path'] ?? '') !== '/'
    ) {
        throw new RuntimeException('Parametry cookie sesji bootstrapu nie zostaly zastosowane.');
    }
    if (!@session_start() || session_status() !== PHP_SESSION_ACTIVE) {
        throw new RuntimeException('Nie udalo sie uruchomic bezpiecznej sesji bootstrapu.');
    }
    if (!isset($_SESSION['te8_bootstrap_csrf']) || !is_string($_SESSION['te8_bootstrap_csrf'])
        || preg_match('/^[a-f0-9]{64}$/', $_SESSION['te8_bootstrap_csrf']) !== 1
    ) {
        $_SESSION['te8_bootstrap_csrf'] = bin2hex(random_bytes(32));
    }
}

function bootstrapRequireSessionIni(string $name, bool $enabled): void
{
    @ini_set($name, $enabled ? '1' : '0');
    $current = strtolower(trim((string) ini_get($name)));
    $isEnabled = in_array($current, ['1', 'on', 'yes', 'true'], true);
    if ($isEnabled !== $enabled) {
        throw new RuntimeException('Serwer PHP nie pozwala ustawic bezpiecznej konfiguracji sesji bootstrapu.');
    }
}

function bootstrapVerifyStartRequest(): void
{
    $expected = bootstrapScalar($_SESSION['te8_bootstrap_csrf'] ?? null);
    $provided = trim(bootstrapScalar($_POST['csrf'] ?? null));
    if ($expected === '' || $provided === '' || !hash_equals($expected, $provided)) {
        throw new RuntimeException('Odrzucono niepotwierdzone uruchomienie bootstrapu.');
    }
    $_SESSION['te8_bootstrap_csrf'] = bin2hex(random_bytes(32));
}

function bootstrapConsumedMarkerPath(): string
{
    $privateRoot = realpath(dirname(__DIR__));
    $bootstrapSha256 = hash_file('sha256', __FILE__);
    if (!is_string($privateRoot) || !is_string($bootstrapSha256)) {
        throw new RuntimeException('Nie mozna potwierdzic prywatnego katalogu bootstrapu.');
    }
    return $privateRoot . DIRECTORY_SEPARATOR . '.te8-bootstrap-consumed-'
        . TE8_INSTALLER_PRODUCT . '-' . TE8_BOOTSTRAP_RELEASE . '-' . substr($bootstrapSha256, 0, 24);
}

function bootstrapLaunchConsumed(): bool
{
    $marker = bootstrapConsumedMarkerPath();
    clearstatcache(true, $marker);
    if (!file_exists($marker) && !is_link($marker)) {
        return false;
    }
    $size = @filesize($marker);
    $permissions = @fileperms($marker);
    if (is_link($marker) || !is_file($marker) || !is_int($size) || $size < 32 || $size > 4096
        || (DIRECTORY_SEPARATOR === '/' && (!is_int($permissions) || ($permissions & 0777) !== 0600))
    ) {
        throw new RuntimeException('Znacznik wykorzystania bootstrapu jest nieprawidlowy.');
    }
    try {
        $record = json_decode((string) file_get_contents($marker), true, 16, JSON_THROW_ON_ERROR);
    } catch (JsonException) {
        throw new RuntimeException('Znacznik wykorzystania bootstrapu jest nieprawidlowy.');
    }
    if (!is_array($record) || array_is_list($record)
        || ($record['schema'] ?? null) !== 'te8-bootstrap-consumed/v1'
        || ($record['product'] ?? null) !== TE8_INSTALLER_PRODUCT
        || ($record['bootstrap_release'] ?? null) !== TE8_BOOTSTRAP_RELEASE
        || ($record['start_mode'] ?? null) !== TE8_BOOTSTRAP_START_MODE
        || !hash_equals((string) hash_file('sha256', __FILE__), (string) ($record['bootstrap_sha256'] ?? ''))
        || preg_match('/^[a-zA-Z0-9][a-zA-Z0-9._+~-]{0,39}$/D', (string) ($record['installer_version'] ?? '')) !== 1
        || preg_match('/^[a-f0-9]{64}$/D', (string) ($record['target_sha256'] ?? '')) !== 1
    ) {
        throw new RuntimeException('Znacznik wykorzystania bootstrapu jest nieprawidlowy.');
    }
    return true;
}

function bootstrapAssertLaunchAvailable(): void
{
    if (bootstrapLaunchConsumed()) {
        throw new RuntimeException('Bootstrap zostal juz wykorzystany.');
    }
}

/** @return resource */
function bootstrapAcquireLaunchLock()
{
    $path = bootstrapConsumedMarkerPath() . '.lock';
    if (is_link($path)) {
        throw new RuntimeException('Blokada uruchomienia bootstrapu jest nieprawidlowa.');
    }
    $handle = @fopen($path, 'c+b');
    if (!is_resource($handle) || !@chmod($path, 0600)) {
        if (is_resource($handle)) {
            fclose($handle);
        }
        throw new RuntimeException('Nie mozna utworzyc blokady uruchomienia bootstrapu.');
    }
    clearstatcache(true, $path);
    $permissions = @fileperms($path);
    if (is_link($path) || !is_file($path)
        || (DIRECTORY_SEPARATOR === '/' && (!is_int($permissions) || ($permissions & 0777) !== 0600))
        || !@flock($handle, LOCK_EX | LOCK_NB)
    ) {
        fclose($handle);
        throw new RuntimeException('Inne uruchomienie bootstrapu jest juz w toku.');
    }
    return $handle;
}

/** @param resource $handle */
function bootstrapReleaseLaunchLock($handle): void
{
    $path = bootstrapConsumedMarkerPath() . '.lock';
    @flock($handle, LOCK_UN);
    @fclose($handle);
    clearstatcache(true, $path);
    if (is_file($path) && !is_link($path)) {
        @unlink($path);
    }
}

/** @param array{url: string, version: string, target_path: string} $installation */
function bootstrapMarkLaunchConsumed(array $installation): void
{
    bootstrapAssertLaunchAvailable();
    $target = realpath((string) ($installation['target_path'] ?? ''));
    if (!is_string($target) || !is_dir($target) || is_link($target)) {
        throw new RuntimeException('Nie mozna zwiazac znacznika z opublikowanym instalatorem.');
    }
    $record = json_encode([
        'schema' => 'te8-bootstrap-consumed/v1',
        'product' => TE8_INSTALLER_PRODUCT,
        'bootstrap_release' => TE8_BOOTSTRAP_RELEASE,
        'start_mode' => TE8_BOOTSTRAP_START_MODE,
        'bootstrap_sha256' => hash_file('sha256', __FILE__),
        'installer_version' => (string) ($installation['version'] ?? ''),
        'target_sha256' => hash('sha256', $target),
        'completed_at' => gmdate('Y-m-d\TH:i:s\Z'),
    ], JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
    $marker = bootstrapConsumedMarkerPath();
    $temporary = $marker . '.tmp-' . bin2hex(random_bytes(12));
    $handle = @fopen($temporary, 'x+b');
    if (!is_resource($handle)) {
        throw new RuntimeException('Nie mozna utworzyc znacznika wykorzystania bootstrapu.');
    }
    $failure = null;
    $locked = false;
    try {
        if (!@chmod($temporary, 0600) || !@flock($handle, LOCK_EX)) {
            throw new RuntimeException('Nie mozna zabezpieczyc znacznika wykorzystania bootstrapu.');
        }
        $locked = true;
        $payload = $record . PHP_EOL;
        $offset = 0;
        while ($offset < strlen($payload)) {
            $written = @fwrite($handle, substr($payload, $offset));
            if (!is_int($written) || $written < 1) {
                throw new RuntimeException('Nie mozna zapisac znacznika wykorzystania bootstrapu.');
            }
            $offset += $written;
        }
        if (!@fflush($handle) || (function_exists('fsync') && !@fsync($handle))) {
            throw new RuntimeException('Nie mozna utrwalic znacznika wykorzystania bootstrapu.');
        }
    } catch (Throwable $exception) {
        $failure = $exception;
    } finally {
        if ($locked) {
            @flock($handle, LOCK_UN);
        }
        if (!@fclose($handle) && $failure === null) {
            $failure = new RuntimeException('Nie mozna zamknac znacznika wykorzystania bootstrapu.');
        }
    }
    if ($failure instanceof Throwable) {
        @unlink($temporary);
        throw $failure;
    }
    clearstatcache(true, $temporary);
    $permissions = @fileperms($temporary);
    if (is_link($temporary) || !is_file($temporary)
        || (DIRECTORY_SEPARATOR === '/' && (!is_int($permissions) || ($permissions & 0777) !== 0600))
        || file_exists($marker) || is_link($marker) || !@rename($temporary, $marker)
    ) {
        @unlink($temporary);
        throw new RuntimeException('Nie mozna opublikowac znacznika wykorzystania bootstrapu.');
    }
    if (!bootstrapLaunchConsumed()) {
        @unlink($marker);
        throw new RuntimeException('Opublikowany znacznik wykorzystania bootstrapu jest nieprawidlowy.');
    }
}

/**
 * @param array{url: string, version: string, target_path: string} $installation
 * @return array{record_path: string, cookie_value: string, cookie_path: string, expires_at: int}
 */
function bootstrapCreateInstallerHandoff(array $installation, string $locale): array
{
    $target = realpath((string) ($installation['target_path'] ?? ''));
    $version = trim((string) ($installation['version'] ?? ''));
    if (!is_string($target) || !is_dir($target) || is_link($target)
        || basename($target) !== TE8_INSTALLER_DIRECTORY
        || preg_match('/^\d+\.\d+\.\d+$/D', $version) !== 1
    ) {
        throw new RuntimeException('Nie mozna przygotowac przekazania kontroli do instalatora.');
    }

    $privateRoot = dirname(__DIR__) . DIRECTORY_SEPARATOR . '.te8-installer-private';
    $handoffRoot = $privateRoot . DIRECTORY_SEPARATOR . 'handoffs';
    bootstrapEnsurePrivateDirectory($privateRoot);
    bootstrapEnsurePrivateDirectory($handoffRoot);

    $recordId = bin2hex(random_bytes(16));
    $secret = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
    $issuedAt = time();
    $expiresAt = $issuedAt + 300;
    $cookiePath = '/' . TE8_INSTALLER_DIRECTORY . '/';
    $record = [
        'schema' => 'te8-installer-handoff/v1',
        'record_id' => $recordId,
        'secret_hash' => hash('sha256', $secret),
        'product' => TE8_INSTALLER_PRODUCT,
        'installer_version' => $version,
        'installer_directory' => TE8_INSTALLER_DIRECTORY,
        'target_hash' => hash('sha256', $target),
        'host_hash' => hash('sha256', bootstrapRequestHost()),
        'cookie_path' => $cookiePath,
        'locale' => in_array($locale, ['pl', 'en'], true) ? $locale : 'pl',
        'issued_at' => $issuedAt,
        'expires_at' => $expiresAt,
    ];
    $json = json_encode($record, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
    $recordPath = $handoffRoot . DIRECTORY_SEPARATOR . $recordId . '.json';
    $temporaryPath = $handoffRoot . DIRECTORY_SEPARATOR . '.new-' . $recordId . '-' . bin2hex(random_bytes(8));
    $handle = @fopen($temporaryPath, 'x');
    if (!is_resource($handle)) {
        throw new RuntimeException('Nie mozna utworzyc prywatnego rekordu przekazania instalatora.');
    }
    $writeFailure = @chmod($temporaryPath, 0600)
        ? null
        : new RuntimeException('Nie mozna zabezpieczyc rekordu przekazania instalatora.');
    $locked = false;
    try {
        if ($writeFailure instanceof Throwable) {
            throw $writeFailure;
        }
        if (!flock($handle, LOCK_EX)) {
            throw new RuntimeException('Nie mozna zapisac prywatnego rekordu przekazania instalatora.');
        }
        $locked = true;
        $payload = $json . PHP_EOL;
        $offset = 0;
        $payloadLength = strlen($payload);
        while ($offset < $payloadLength) {
            $written = @fwrite($handle, substr($payload, $offset));
            if (!is_int($written) || $written < 1) {
                throw new RuntimeException('Nie mozna zapisac prywatnego rekordu przekazania instalatora.');
            }
            $offset += $written;
        }
        if (!@fflush($handle)) {
            throw new RuntimeException('Nie mozna utrwalic prywatnego rekordu przekazania instalatora.');
        }
        if (function_exists('fsync') && !@fsync($handle)) {
            throw new RuntimeException('Nie mozna zsynchronizowac prywatnego rekordu przekazania instalatora.');
        }
    } catch (Throwable $exception) {
        $writeFailure = $exception;
    } finally {
        if ($locked) {
            @flock($handle, LOCK_UN);
        }
        if (!@fclose($handle) && $writeFailure === null) {
            $writeFailure = new RuntimeException('Nie mozna zamknac prywatnego rekordu przekazania instalatora.');
        }
    }
    if ($writeFailure instanceof Throwable) {
        @unlink($temporaryPath);
        throw $writeFailure;
    }
    clearstatcache(true, $temporaryPath);
    $permissions = @fileperms($temporaryPath);
    if (is_link($temporaryPath)
        || !is_file($temporaryPath)
        || (DIRECTORY_SEPARATOR === '/' && (!is_int($permissions) || ($permissions & 0777) !== 0600))
    ) {
        @unlink($temporaryPath);
        throw new RuntimeException('Rekord przekazania instalatora ma nieprawidlowe uprawnienia.');
    }
    if (file_exists($recordPath) || is_link($recordPath) || !@rename($temporaryPath, $recordPath)) {
        @unlink($temporaryPath);
        throw new RuntimeException('Nie mozna opublikowac rekordu przekazania instalatora.');
    }
    clearstatcache(true, $recordPath);
    $publishedPermissions = @fileperms($recordPath);
    $publishedContents = @file_get_contents($recordPath);
    if (is_link($recordPath) || !is_file($recordPath)
        || !is_int($publishedPermissions)
        || (DIRECTORY_SEPARATOR === '/' && ($publishedPermissions & 0777) !== 0600)
        || !is_string($publishedContents)
        || !hash_equals($json . PHP_EOL, $publishedContents)
    ) {
        @unlink($recordPath);
        throw new RuntimeException('Opublikowany rekord przekazania instalatora jest nieprawidlowy.');
    }

    return [
        'record_path' => $recordPath,
        'cookie_value' => $recordId . '.' . $secret,
        'cookie_path' => $cookiePath,
        'expires_at' => $expiresAt,
    ];
}

/** @param array{record_path: string, cookie_value: string, cookie_path: string, expires_at: int} $handoff */
function bootstrapSetInstallerHandoffCookie(array $handoff): void
{
    $value = (string) ($handoff['cookie_value'] ?? '');
    $path = (string) ($handoff['cookie_path'] ?? '');
    if (preg_match('/^[a-f0-9]{32}\.[A-Za-z0-9_-]{43}$/D', $value) !== 1
        || $path !== '/' . TE8_INSTALLER_DIRECTORY . '/'
        || !setcookie('TE8INSTALLERHANDOFF', $value, [
            'expires' => (int) $handoff['expires_at'],
            'path' => $path,
            'secure' => true,
            'httponly' => true,
            'samesite' => 'Strict',
        ])
    ) {
        throw new RuntimeException('Nie mozna bezpiecznie przekazac sesji do instalatora.');
    }
}

/** @param array{record_path: string, cookie_value: string, cookie_path: string, expires_at: int} $handoff */
function bootstrapDiscardInstallerHandoff(array $handoff): void
{
    $recordPath = (string) ($handoff['record_path'] ?? '');
    $handoffRoot = dirname(__DIR__) . DIRECTORY_SEPARATOR . '.te8-installer-private' . DIRECTORY_SEPARATOR . 'handoffs';
    if (dirname($recordPath) === $handoffRoot
        && preg_match('/^[a-f0-9]{32}\.json$/D', basename($recordPath)) === 1
        && (is_file($recordPath) || is_link($recordPath))
    ) {
        @unlink($recordPath);
    }
    $cookiePath = (string) ($handoff['cookie_path'] ?? ('/' . TE8_INSTALLER_DIRECTORY . '/'));
    setcookie('TE8INSTALLERHANDOFF', '', [
        'expires' => time() - 3600,
        'path' => $cookiePath,
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Strict',
    ]);
}

function bootstrapEnsurePrivateDirectory(string $directory): void
{
    $parent = realpath(dirname($directory));
    if (!is_string($parent)) {
        throw new RuntimeException('Nie mozna potwierdzic nadrzednego katalogu prywatnego instalatora.');
    }
    if (is_link($directory) || (file_exists($directory) && !is_dir($directory))) {
        throw new RuntimeException('Prywatny katalog instalatora ma niebezpieczna postac.');
    }
    if (!is_dir($directory) && !mkdir($directory, 0700, true) && !is_dir($directory)) {
        throw new RuntimeException('Nie mozna utworzyc prywatnego katalogu instalatora.');
    }
    $resolved = realpath($directory);
    if (!is_string($resolved) || dirname($resolved) !== $parent) {
        throw new RuntimeException('Prywatny katalog instalatora ma nieprawidlowa sciezke.');
    }
    if (DIRECTORY_SEPARATOR === '/') {
        if (!@chmod($directory, 0700)) {
            throw new RuntimeException('Nie mozna zabezpieczyc prywatnego katalogu instalatora.');
        }
        $permissions = @fileperms($directory);
        if (!is_int($permissions) || ($permissions & 0777) !== 0700) {
            throw new RuntimeException('Prywatny katalog instalatora ma nieprawidlowe uprawnienia.');
        }
    }
}

function bootstrapInstallerHandoffMode(): string
{
    $mode = TE8_INSTALLER_HANDOFF_MODE;
    if (!in_array($mode, ['cookie-v1', 'external-token'], true)
        || preg_match('/^[a-z0-9][a-z0-9._-]{1,63}$/D', TE8_INSTALLER_PRODUCT) !== 1
        || preg_match('/^[a-z0-9][a-z0-9_]{1,63}$/D', TE8_INSTALLER_DIRECTORY) !== 1
    ) {
        throw new RuntimeException('Bootstrap ma nieprawidlowy tryb przekazania kontroli do instalatora.');
    }

    $profiles = [
        'install-system-te8' => ['directory' => 'install_system_te8', 'mode' => 'cookie-v1'],
        'install-sso' => ['directory' => 'install_sso', 'mode' => 'cookie-v1'],
        'install-te8-pl' => ['directory' => 'install_te8_pl', 'mode' => 'cookie-v1'],
        'install-update' => ['directory' => 'install_update', 'mode' => 'external-token'],
    ];
    $profile = $profiles[TE8_INSTALLER_PRODUCT] ?? null;
    if (is_array($profile)
        && ($mode !== $profile['mode'] || TE8_INSTALLER_DIRECTORY !== $profile['directory'])
    ) {
        throw new RuntimeException('Produkt instalatora ma nieprawidlowy katalog albo tryb przekazania kontroli.');
    }
    if ($mode === 'external-token' && TE8_INSTALLER_PRODUCT !== 'install-update') {
        throw new RuntimeException('Tryb external-token jest przeznaczony wylacznie dla instalatora update.te8.pl.');
    }

    return $mode;
}

function bootstrapRequestHost(): string
{
    $header = trim(bootstrapScalar($_SERVER['HTTP_HOST'] ?? null));
    if ($header === '' || str_contains($header, ',') || preg_match('/[\x00-\x20\x7F]/', $header) === 1
        || preg_match('/^(?:[a-z0-9](?:[a-z0-9.-]{0,251}[a-z0-9])?|\[[0-9a-f:.]+\])(?::([0-9]{1,5}))?$/Di', $header, $match) !== 1
        || (isset($match[1]) && $match[1] !== '' && ((int) $match[1] < 1 || (int) $match[1] > 65535))
    ) {
        throw new RuntimeException('Nie mozna potwierdzic hosta instalatora.');
    }
    $host = parse_url('https://' . $header, PHP_URL_HOST);
    $host = is_string($host) ? strtolower(trim(rtrim($host, '.'), '[]')) : '';
    if ($host === '' || (filter_var($host, FILTER_VALIDATE_IP) === false
        && preg_match('/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/D', $host) !== 1)
    ) {
        throw new RuntimeException('Host instalatora ma nieprawidlowy format.');
    }
    return $host;
}

function bootstrapLocale(): string
{
    $requested = strtolower(trim(bootstrapScalar($_GET['lang'] ?? null)));
    if (in_array($requested, ['pl', 'en'], true)) {
        if (bootstrapHttpsReady()) {
            setcookie('TE8BOOTSTRAPLANG', $requested, [
                'expires' => time() + 31536000,
                'path' => '/',
                'secure' => true,
                'httponly' => false,
                'samesite' => 'Lax',
            ]);
        }
        return $requested;
    }
    $cookie = strtolower(trim(bootstrapScalar($_COOKIE['TE8BOOTSTRAPLANG'] ?? null)));
    return in_array($cookie, ['pl', 'en'], true) ? $cookie : 'pl';
}

function bootstrapScalar(mixed $value, string $fallback = ''): string
{
    return is_string($value) || is_int($value) || is_float($value)
        ? (string) $value
        : $fallback;
}

function bootstrapText(string $polish, string $english, string $locale): string
{
    return $locale === 'en' ? $english : $polish;
}

function renderPage(
    ?string $error,
    string $locale,
    ?string $selectedInstallerVersion,
    bool $bootstrapReady,
    bool $bootstrapConsumed
): void
{
    header('Content-Type: text/html; charset=UTF-8');
    ?>
<!doctype html>
<html lang="<?= h($locale) ?>">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?= h(bootstrapText('Instalator ' . TE8_INSTALLER_NAME, TE8_INSTALLER_NAME . ' installer', $locale)) ?></title>
    <style>
        :root{--bg:#f9f4e8;--paper:#fffaf0;--ink:#211d18;--muted:#6d6258;--line:#dfd2bf;--accent:#9c4f2f;--danger:#8b2339;--ok:#1e6f4f}
        *{box-sizing:border-box}body{margin:0;font-family:Segoe UI,Arial,sans-serif;background:radial-gradient(circle at 12% 0%,rgba(156,79,47,.13),transparent 28rem),var(--bg);color:var(--ink)}
        main{max-width:920px;margin:0 auto;padding:36px 18px 64px;display:grid;gap:18px}
        .hero,.card{border:1px solid var(--line);border-radius:24px;background:rgba(255,250,240,.92);box-shadow:0 18px 48px rgba(72,52,36,.12)}
        .hero{padding:28px}.card{padding:24px;display:grid;gap:16px}
        .eyebrow{text-transform:uppercase;letter-spacing:.18em;font-size:12px;color:var(--accent);font-weight:700}
        h1{font-size:clamp(34px,5vw,58px);line-height:.96;margin:8px 0 10px}h2{margin:0;font-size:22px}p,li{line-height:1.6;color:var(--muted)}
        ul{margin:0;padding-left:20px;display:grid;gap:8px}.notice{border:1px solid rgba(30,111,79,.22);border-radius:18px;background:rgba(30,111,79,.08);padding:14px 16px;color:var(--ok)}
        .error{border:1px solid rgba(139,35,57,.28);border-radius:18px;background:rgba(139,35,57,.08);color:var(--danger);padding:14px 16px}
        button{border:0;border-radius:999px;padding:14px 22px;background:linear-gradient(135deg,var(--accent),#c26e47);color:#fff8f1;font:inherit;cursor:pointer}.language{display:flex;justify-content:flex-end;gap:8px}.language a{padding:7px 10px;border:1px solid var(--line);border-radius:999px;color:var(--ink);text-decoration:none}
        code{font-family:Consolas,monospace;font-size:.94em}
        @media(max-width:760px){main{padding:20px 12px 44px}.hero,.card{border-radius:18px;padding:18px}}
    </style>
</head>
<body>
<main>
    <nav class="language" aria-label="<?= h(bootstrapText('Wybór języka', 'Language selection', $locale)) ?>">
        <a href="?lang=pl" lang="pl"<?= $locale === 'pl' ? ' aria-current="page"' : '' ?>>PL</a>
        <a href="?lang=en" lang="en"<?= $locale === 'en' ? ' aria-current="page"' : '' ?>>EN</a>
    </nav>
    <section class="hero">
        <div class="eyebrow">TE8 install bootstrap <?= h(TE8_BOOTSTRAP_RELEASE) ?></div>
        <h1><?= h(bootstrapText('Instalator ' . TE8_INSTALLER_NAME, TE8_INSTALLER_NAME . ' installer', $locale)) ?></h1>
        <p><?= h(bootstrapText(
            'Ten plik pobierze właściwy, podpisany instalator i rozpakuje go do katalogu ',
            'This file downloads the correct signed installer and extracts it into ',
            $locale
        )) ?><code><?= h(TE8_INSTALLER_DIRECTORY) ?></code><?= h(bootstrapText(' i przejdzie do kreatora.', ' and opens its setup wizard.', $locale)) ?></p>
        <p><?= h(bootstrapText('Wybrana wersja instalatora:', 'Selected installer version:', $locale)) ?> <code><?= h($selectedInstallerVersion ?? bootstrapText('najnowsza', 'latest', $locale)) ?></code>.</p>
    </section>

    <section class="card">
        <?php if ($error !== null): ?>
            <div class="error"><?= h($error) ?></div>
        <?php endif; ?>
        <div class="notice"><?= h(bootstrapText(
            'Kliknij „Rozpocznij instalację”. Bootstrap pobierze wyłącznie podpisany instalator, sprawdzi go i otworzy kreator.',
            'Click “Start installation”. The bootstrap downloads only the signed installer, verifies it, and opens the setup wizard.',
            $locale
        )) ?></div>
        <?php if (!bootstrapHttpsReady()): ?>
            <div class="error"><?= h(bootstrapText(
                'Otwórz ten adres przez HTTPS. Przycisk instalacji jest dostępny wyłącznie w bezpiecznym połączeniu.',
                'Open this address over HTTPS. The installation button is available only over a secure connection.',
                $locale
            )) ?></div>
        <?php endif; ?>
        <h2><?= h(bootstrapText('Prosta instalacja Home', 'Simple Home installation', $locale)) ?></h2>
        <ul>
            <li><?= h(bootstrapText('Umieść ten plik bezpośrednio w przygotowanym public_html właściwej domeny.', 'Place this file directly in the prepared public_html of the correct domain.', $locale)) ?></li>
            <li><?= h(bootstrapText('Otwórz install.php przez HTTPS i kliknij „Rozpocznij instalację”.', 'Open install.php over HTTPS and click “Start installation”.', $locale)) ?></li>
            <li><?= h(bootstrapText('Przygotuj dane istniejącej bazy i osobnego użytkownika, jeżeli kreator danego produktu ich wymaga.', 'Prepare an existing database and a dedicated database user if this product wizard requires them.', $locale)) ?></li>
            <li><?= h(bootstrapText('Po przekazaniu do kreatora bootstrap blokuje ponowne użycie i usuwa własny install.php.', 'After handing off to the wizard, the bootstrap blocks reuse and removes its own install.php.', $locale)) ?></li>
        </ul>
        <?php if ($bootstrapConsumed): ?>
            <div class="notice"><?= h(bootstrapText(
                'Instalator został już przygotowany. Przejdź do otwartego kreatora instalacji.',
                'The installer has already been prepared. Continue to the installation wizard.',
                $locale
            )) ?> <a href="./<?= h(TE8_INSTALLER_DIRECTORY) ?>/"><?= h(bootstrapText('Otwórz kreator', 'Open the wizard', $locale)) ?></a></div>
        <?php elseif ($bootstrapReady): ?>
        <form method="post" autocomplete="off">
            <input type="hidden" name="csrf" value="<?= h(bootstrapScalar($_SESSION['te8_bootstrap_csrf'] ?? null)) ?>">
            <button type="submit"><?= h(bootstrapText('Rozpocznij instalację', 'Start installation', $locale)) ?></button>
        </form>
        <?php endif; ?>
    </section>
</main>
</body>
</html>
    <?php
}

function h(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
