<?php

declare(strict_types=1);

use Atlas\Client\Service\ClientActivationService;
use Atlas\Client\Service\ClientIntegrationBootstrap;
use Atlas\Client\Service\ClientLicenseTokenVerifier;

header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
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'; " .
    "frame-ancestors 'none'; " .
    "base-uri 'none'"
);

final class AtlasWebInstaller
{
    private const APP_VERSION =
        '8.0.2.2';

    private const LICENSE_KEY_ID =
        'LIC-39D6F99A7D1C';

    private const MANIFEST_SHA256 =
        'fbb55795f58681146ff9b7eb363791a5f6a08c53d38b4b3269e09c22a534e4b4';

    private const PAYLOAD_SHA256 =
        '33eba37bd42419b306abb420fc311ff598e4b9916afdbf4fe55d73de0d1aea62';

    private const MAX_LICENSE_KEY_BYTES =
        128;

    private const MIN_RETRY_SECONDS =
        10;

    private string $chatRoot;
    private string $assetRoot;
    private string $privateRoot;
    private string $domain;

    public function __construct(
        ?string $chatRoot = null,
        ?string $assetRoot = null
    ) {
        $chatRoot ??= __DIR__;

        $realChatRoot =
            realpath($chatRoot);

        if (
            $realChatRoot === false ||
            !is_dir($realChatRoot) ||
            is_link($chatRoot)
        ) {
            throw new RuntimeException(
                'Installer root is unavailable.'
            );
        }

        $this->chatRoot =
            $realChatRoot;

        $assetRoot ??=
            $this->chatRoot .
            '/atlas-installer-assets';

        $this->assetRoot =
            $assetRoot;

        $this->privateRoot =
            $this->discoverPrivateRoot(
                $this->chatRoot
            );

        $this->domain =
            $this->requestDomain();
    }

    public function handle(): never
    {
        $this->assertWebRequirements();
        $this->startSecureSession();

        $state =
            $this->installationState();

        $method =
            strtoupper(
                (string) (
                    $_SERVER['REQUEST_METHOD']
                    ?? ''
                )
            );

        if (
            $method !== 'GET' &&
            $method !== 'POST'
        ) {
            header('Allow: GET, POST');

            $this->render(
                405,
                'Method not allowed',
                'Only GET and POST requests are accepted.',
                false
            );
        }

        if ($state === 'ACTIVE') {
            $this->render(
                200,
                'Atlas is already activated',
                'The private Atlas client is installed and active.',
                false
            );
        }

        if ($method === 'GET') {
            $this->render(
                200,
                'Install and activate Atlas',
                'Enter the one-time license key created in the Atlas licensing panel.',
                true
            );
        }

        $this->verifyCsrf();
        $this->enforceRetryThrottle();

        $licenseKey =
            isset($_POST['license_key']) &&
            is_string($_POST['license_key'])
                ? strtoupper(
                    trim(
                        $_POST['license_key']
                    )
                )
                : '';

        if (
            $licenseKey === '' ||
            strlen($licenseKey) >
                self::MAX_LICENSE_KEY_BYTES ||
            !preg_match(
                '/^ATL-[0-9A-HJKMNP-TV-Z]{12}' .
                '(?:-[0-9A-HJKMNP-TV-Z]{5}){6}$/',
                $licenseKey
            )
        ) {
            $this->rotateCsrf();

            $this->render(
                400,
                'Invalid license key',
                'Check the license key and try again.',
                true
            );
        }

        $_SESSION[
            'atlas_installer_last_attempt'
        ] = time();

        try {
            if ($state === 'ABSENT') {
                $this->installPrivateClient();
            } elseif ($state !== 'PENDING') {
                throw new RuntimeException(
                    'Unsafe existing Atlas installation.'
                );
            }

            $result =
                $this->activate(
                    $licenseKey
                );

            if (
                ($result['ok'] ?? false) !== true ||
                ($result['code'] ?? '') !==
                    'ACTIVATED'
            ) {
                throw new RuntimeException(
                    'Activation did not complete.'
                );
            }

            $this->rotateCsrf();

            $this->render(
                200,
                'Atlas activated successfully',
                'Installation, domain verification and license activation completed.',
                false
            );

        } catch (Throwable $exception) {
            $fingerprint =
                hash(
                    'sha256',
                    get_class($exception) .
                    "\n" .
                    $exception->getMessage()
                );

            error_log(
                'Atlas web installer failure [' .
                $fingerprint .
                '].'
            );

            $this->rotateCsrf();

            $this->render(
                500,
                'Atlas activation failed',
                'The installation can be retried safely. Reference: ' .
                    substr($fingerprint, 0, 16),
                true
            );

        } finally {
            sodium_memzero(
                $licenseKey
            );
        }
    }

    private function assertWebRequirements(): void
    {
        $https =
            isset($_SERVER['HTTPS']) &&
            strtolower(
                (string)$_SERVER['HTTPS']
            ) !== 'off' &&
            (string)$_SERVER['HTTPS'] !== '';

        if (!$https) {
            throw new RuntimeException(
                'HTTPS is required.'
            );
        }

        if (
            PHP_VERSION_ID < 80200 ||
            !extension_loaded('curl') ||
            !extension_loaded('sodium') ||
            !extension_loaded('zip') ||
            !extension_loaded('json')
        ) {
            throw new RuntimeException(
                'Server requirements are unavailable.'
            );
        }

        foreach (
            [
                $this->assetRoot,
                $this->assetRoot .
                    '/manifest.json',
                $this->assetRoot .
                    '/payload.zip',
            ] as $path
        ) {
            if (
                (
                    $path === $this->assetRoot &&
                    !is_dir($path)
                ) ||
                (
                    $path !== $this->assetRoot &&
                    !is_file($path)
                ) ||
                is_link($path)
            ) {
                throw new RuntimeException(
                    'Installer assets are unavailable.'
                );
            }
        }

        if (
            !hash_equals(
                self::MANIFEST_SHA256,
                hash_file(
                    'sha256',
                    $this->assetRoot .
                        '/manifest.json'
                )
            ) ||
            !hash_equals(
                self::PAYLOAD_SHA256,
                hash_file(
                    'sha256',
                    $this->assetRoot .
                        '/payload.zip'
                )
            )
        ) {
            throw new RuntimeException(
                'Installer asset integrity check failed.'
            );
        }
    }

    private function discoverPrivateRoot(
        string $chatRoot
    ): string {
        $current =
            $chatRoot;

        for ($depth = 0; $depth < 8; $depth++) {
            if (
                basename($current) ===
                    'public_html'
            ) {
                return
                    dirname($current) .
                    '/.atlas-client';
            }

            $parent =
                dirname($current);

            if ($parent === $current) {
                break;
            }

            $current =
                $parent;
        }

        throw new RuntimeException(
            'Unable to discover a private installation root.'
        );
    }

    private function requestDomain(): string
    {
        $host =
            strtolower(
                trim(
                    (string) (
                        $_SERVER['HTTP_HOST']
                        ?? ''
                    )
                )
            );

        if (
            str_contains($host, ':')
        ) {
            $parsed =
                parse_url(
                    'https://' . $host,
                    PHP_URL_HOST
                );

            $host =
                is_string($parsed)
                    ? strtolower($parsed)
                    : '';
        }

        $host =
            rtrim(
                $host,
                '.'
            );

        if (
            $host === '' ||
            strlen($host) > 253 ||
            filter_var(
                $host,
                FILTER_VALIDATE_DOMAIN,
                FILTER_FLAG_HOSTNAME
            ) === false ||
            filter_var(
                $host,
                FILTER_VALIDATE_IP
            ) !== false
        ) {
            throw new RuntimeException(
                'Invalid installation domain.'
            );
        }

        return $host;
    }

    private function installationState(): string
    {
        if (
            !file_exists($this->privateRoot) &&
            !is_link($this->privateRoot)
        ) {
            return 'ABSENT';
        }

        if (
            !is_dir($this->privateRoot) ||
            is_link($this->privateRoot)
        ) {
            return 'UNSAFE';
        }

        $marker =
            $this->privateRoot .
            '/state/distribution.json';

        $token =
            $this->privateRoot .
            '/state/license.token';

        if (
            is_file($token) &&
            !is_link($token)
        ) {
            return 'ACTIVE';
        }

        if (
            is_file($marker) &&
            !is_link($marker)
        ) {
            return 'PENDING';
        }

        return 'UNSAFE';
    }
    private function startSecureSession(): void
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            return;
        }

        session_name('ATLAS_INSTALLER');

        session_set_cookie_params([
            'lifetime' => 0,
            'path' => '/',
            'domain' => '',
            'secure' => true,
            'httponly' => true,
            'samesite' => 'Strict',
        ]);

        if (!session_start()) {
            throw new RuntimeException(
                'Unable to start installer session.'
            );
        }

        if (
            !isset($_SESSION['atlas_installer_started']) ||
            !is_int($_SESSION['atlas_installer_started'])
        ) {
            session_regenerate_id(true);

            $_SESSION['atlas_installer_started'] =
                time();
        }

        $this->csrf();
    }

    private function csrf(): string
    {
        $token =
            $_SESSION['atlas_installer_csrf']
            ?? null;

        if (
            !is_string($token) ||
            !preg_match(
                '/^[a-f0-9]{64}$/',
                $token
            )
        ) {
            $token =
                bin2hex(
                    random_bytes(32)
                );

            $_SESSION['atlas_installer_csrf'] =
                $token;
        }

        return $token;
    }

    private function verifyCsrf(): void
    {
        $sessionToken =
            $_SESSION['atlas_installer_csrf']
            ?? null;

        $requestToken =
            $_POST['csrf_token']
            ?? null;

        if (
            !is_string($sessionToken) ||
            !is_string($requestToken) ||
            strlen($requestToken) !== 64 ||
            !hash_equals(
                $sessionToken,
                $requestToken
            )
        ) {
            throw new RuntimeException(
                'Invalid installer request token.'
            );
        }
    }

    private function rotateCsrf(): void
    {
        $_SESSION['atlas_installer_csrf'] =
            bin2hex(
                random_bytes(32)
            );
    }

    private function enforceRetryThrottle(): void
    {
        $lastAttempt =
            $_SESSION[
                'atlas_installer_last_attempt'
            ] ?? 0;

        if (
            !is_int($lastAttempt) &&
            !ctype_digit(
                (string)$lastAttempt
            )
        ) {
            $lastAttempt = 0;
        }

        if (
            (int)$lastAttempt > 0 &&
            time() - (int)$lastAttempt <
                self::MIN_RETRY_SECONDS
        ) {
            throw new RuntimeException(
                'Installer retry limit reached.'
            );
        }
    }

    private function loadManifest(): array
    {
        $manifestFile =
            $this->assetRoot .
            '/manifest.json';

        if (
            !is_file($manifestFile) ||
            is_link($manifestFile) ||
            filesize($manifestFile) === false ||
            filesize($manifestFile) > 131072
        ) {
            throw new RuntimeException(
                'Invalid installer manifest file.'
            );
        }

        $raw =
            file_get_contents(
                $manifestFile
            );

        if (
            !is_string($raw) ||
            $raw === '' ||
            !hash_equals(
                self::MANIFEST_SHA256,
                hash('sha256', $raw)
            )
        ) {
            throw new RuntimeException(
                'Installer manifest integrity mismatch.'
            );
        }

        try {
            $manifest =
                json_decode(
                    $raw,
                    true,
                    32,
                    JSON_THROW_ON_ERROR
                );
        } catch (Throwable) {
            throw new RuntimeException(
                'Invalid installer manifest.'
            );
        }

        if (!is_array($manifest)) {
            throw new RuntimeException(
                'Invalid installer manifest structure.'
            );
        }

        $keys =
            array_keys($manifest);

        sort($keys);

        $expectedKeys = [
            'application_version',
            'distribution_version',
            'excluded_runtime_roots',
            'private_payload',
            'public_integration',
            'schema',
        ];

        sort($expectedKeys);

        if (
            $keys !== $expectedKeys ||
            ($manifest['schema'] ?? '') !==
                'ATLAS-CLIENT-DISTRIBUTION-V1' ||
            ($manifest['application_version'] ?? '') !==
                self::APP_VERSION ||
            !is_string(
                $manifest['distribution_version']
                ?? null
            ) ||
            !preg_match(
                '/^[A-Za-z0-9][A-Za-z0-9._-]{0,49}$/',
                $manifest['distribution_version']
            ) ||
            !is_array(
                $manifest['private_payload']
                ?? null
            ) ||
            count($manifest['private_payload']) !== 33 ||
            !is_array(
                $manifest['public_integration']
                ?? null
            ) ||
            count($manifest['public_integration']) !== 5 ||
            !is_array(
                $manifest['excluded_runtime_roots']
                ?? null
            ) ||
            count(
                $manifest['excluded_runtime_roots']
            ) !== 7
        ) {
            throw new RuntimeException(
                'Unexpected installer manifest contract.'
            );
        }

        $this->assertManifestEntries(
            $manifest['private_payload'],
            true
        );

        $this->assertManifestEntries(
            $manifest['public_integration'],
            false
        );

        return $manifest;
    }

    private function assertManifestEntries(
        array $entries,
        bool $private
    ): void {
        foreach ($entries as $relative => $metadata) {
            if (
                !is_string($relative) ||
                !$this->isSafeRelativePath(
                    $relative
                ) ||
                !is_array($metadata)
            ) {
                throw new RuntimeException(
                    'Invalid installer manifest entry.'
                );
            }

            $keys =
                array_keys($metadata);

            sort($keys);

            if (
                $keys !== [
                    'bytes',
                    'mode',
                    'sha256',
                ] ||
                !is_string(
                    $metadata['sha256']
                    ?? null
                ) ||
                !preg_match(
                    '/^[a-f0-9]{64}$/',
                    $metadata['sha256']
                ) ||
                !is_int(
                    $metadata['bytes']
                    ?? null
                ) ||
                $metadata['bytes'] <= 0 ||
                $metadata['bytes'] > 2097152
            ) {
                throw new RuntimeException(
                    'Invalid installer file metadata.'
                );
            }

            $mode =
                (string) (
                    $metadata['mode']
                    ?? ''
                );

            if (
                $private
                    ? !in_array(
                        $mode,
                        ['400', '600'],
                        true
                    )
                    : $mode !== '644'
            ) {
                throw new RuntimeException(
                    'Invalid installer file mode.'
                );
            }
        }
    }

    private function assertPublicIntegration(
        array $manifest
    ): void {
        foreach (
            $manifest['public_integration']
            as $relative => $metadata
        ) {
            $file =
                $this->chatRoot .
                DIRECTORY_SEPARATOR .
                str_replace(
                    '/',
                    DIRECTORY_SEPARATOR,
                    $relative
                );

            if (
                !is_file($file) ||
                is_link($file) ||
                filesize($file) !==
                    $metadata['bytes'] ||
                !hash_equals(
                    $metadata['sha256'],
                    (string)hash_file(
                        'sha256',
                        $file
                    )
                )
            ) {
                throw new RuntimeException(
                    'Public Atlas integration mismatch.'
                );
            }
        }
    }

    private function installPrivateClient(): void
    {
        $manifest =
            $this->loadManifest();

        $this->assertPublicIntegration(
            $manifest
        );

        $archive =
            $this->assetRoot .
            '/payload.zip';

        if (
            !is_file($archive) ||
            is_link($archive) ||
            !hash_equals(
                self::PAYLOAD_SHA256,
                (string)hash_file(
                    'sha256',
                    $archive
                )
            )
        ) {
            throw new RuntimeException(
                'Installer payload integrity mismatch.'
            );
        }

        $parent =
            dirname(
                $this->privateRoot
            );

        $resolvedParent =
            realpath($parent);

        if (
            $resolvedParent === false ||
            !is_dir($resolvedParent) ||
            is_link($parent) ||
            !is_writable($resolvedParent)
        ) {
            throw new RuntimeException(
                'Private installation parent is unavailable.'
            );
        }

        $parentStat =
            stat($resolvedParent);

        $chatStat =
            stat($this->chatRoot);

        if (
            !is_array($parentStat) ||
            !is_array($chatStat) ||
            (int)$parentStat['uid'] !==
                (int)$chatStat['uid']
        ) {
            throw new RuntimeException(
                'Private installation ownership mismatch.'
            );
        }

        if (
            file_exists($this->privateRoot) ||
            is_link($this->privateRoot)
        ) {
            throw new RuntimeException(
                'Private Atlas installation already exists.'
            );
        }

        $stage =
            $resolvedParent .
            '/.atlas-client.install-' .
            bin2hex(
                random_bytes(12)
            );

        if (
            file_exists($stage) ||
            is_link($stage) ||
            !mkdir($stage, 0700, false)
        ) {
            throw new RuntimeException(
                'Unable to create installation staging.'
            );
        }

        chmod($stage, 0700);

        $zip =
            new ZipArchive();

        try {
            if (
                $zip->open(
                    $archive,
                    ZipArchive::RDONLY
                ) !== true ||
                $zip->numFiles !== 33
            ) {
                throw new RuntimeException(
                    'Invalid installer payload archive.'
                );
            }

            $archiveNames = [];

            for (
                $index = 0;
                $index < $zip->numFiles;
                $index++
            ) {
                $name =
                    $zip->getNameIndex(
                        $index
                    );

                if (
                    !is_string($name) ||
                    !$this->isSafeRelativePath(
                        $name
                    ) ||
                    isset($archiveNames[$name]) ||
                    !array_key_exists(
                        $name,
                        $manifest['private_payload']
                    )
                ) {
                    throw new RuntimeException(
                        'Unexpected installer archive entry.'
                    );
                }

                $archiveNames[$name] = true;
            }

            if (
                count($archiveNames) !==
                    count(
                        $manifest['private_payload']
                    )
            ) {
                throw new RuntimeException(
                    'Incomplete installer payload archive.'
                );
            }

            foreach (
                $manifest['private_payload']
                as $relative => $metadata
            ) {
                if (!isset($archiveNames[$relative])) {
                    throw new RuntimeException(
                        'Installer payload file is missing.'
                    );
                }

                $content =
                    $zip->getFromName(
                        $relative,
                        $metadata['bytes'] + 1
                    );

                if (
                    !is_string($content) ||
                    strlen($content) !==
                        $metadata['bytes'] ||
                    !hash_equals(
                        $metadata['sha256'],
                        hash(
                            'sha256',
                            $content
                        )
                    )
                ) {
                    throw new RuntimeException(
                        'Installer payload file mismatch.'
                    );
                }

                $target =
                    $stage .
                    DIRECTORY_SEPARATOR .
                    str_replace(
                        '/',
                        DIRECTORY_SEPARATOR,
                        $relative
                    );

                $directory =
                    dirname($target);

                $this->ensurePrivateDirectory(
                    $directory,
                    $stage
                );

                $handle =
                    fopen(
                        $target,
                        'x+b'
                    );

                if ($handle === false) {
                    throw new RuntimeException(
                        'Unable to create installed file.'
                    );
                }

                try {
                    if (
                        !flock(
                            $handle,
                            LOCK_EX
                        ) ||
                        fwrite(
                            $handle,
                            $content
                        ) !== strlen($content) ||
                        !fflush($handle)
                    ) {
                        throw new RuntimeException(
                            'Unable to write installed file.'
                        );
                    }
                } finally {
                    fclose($handle);
                }

                $mode =
                    octdec(
                        (string)$metadata['mode']
                    );

                if (
                    !chmod($target, $mode) ||
                    hash_file(
                        'sha256',
                        $target
                    ) !== $metadata['sha256']
                ) {
                    throw new RuntimeException(
                        'Installed file verification failed.'
                    );
                }

                sodium_memzero($content);
            }

            foreach (
                [
                    'keys',
                    'state',
                    'storage',
                    'modules',
                    'packages',
                    'staging',
                    'verification',
                ] as $directory
            ) {
                $runtime =
                    $stage .
                    DIRECTORY_SEPARATOR .
                    $directory;

                if (
                    file_exists($runtime) ||
                    is_link($runtime) ||
                    !mkdir(
                        $runtime,
                        0700,
                        false
                    )
                ) {
                    throw new RuntimeException(
                        'Unable to create private runtime directory.'
                    );
                }

                chmod($runtime, 0700);
            }

            $this->createInstallationKeypair(
                $stage
            );

            $this->writeDistributionMarker(
                $stage,
                $manifest
            );

            if (
                !rename(
                    $stage,
                    $this->privateRoot
                )
            ) {
                throw new RuntimeException(
                    'Unable to promote private installation.'
                );
            }

        } catch (Throwable $exception) {
            $this->removePrivateTree(
                $stage
            );

            throw $exception;

        } finally {
            $zip->close();
        }
    }

    private function isSafeRelativePath(
        string $path
    ): bool {
        if (
            $path === '' ||
            strlen($path) > 240 ||
            str_starts_with($path, '/') ||
            str_ends_with($path, '/') ||
            str_contains($path, '\\') ||
            str_contains($path, "\0") ||
            preg_match('/[\x00-\x1F\x7F]/', $path)
        ) {
            return false;
        }

        $segments =
            explode('/', $path);

        foreach ($segments as $segment) {
            if (
                $segment === '' ||
                $segment === '.' ||
                $segment === '..' ||
                strlen($segment) > 100
            ) {
                return false;
            }
        }

        return true;
    }

    private function ensurePrivateDirectory(
        string $directory,
        string $stage
    ): void {
        $prefix =
            rtrim(
                $stage,
                DIRECTORY_SEPARATOR
            ) .
            DIRECTORY_SEPARATOR;

        if (
            !str_starts_with(
                $directory .
                    DIRECTORY_SEPARATOR,
                $prefix
            )
        ) {
            throw new RuntimeException(
                'Installed directory escaped staging.'
            );
        }

        $relative =
            substr(
                $directory,
                strlen($prefix)
            );

        if ($relative === false) {
            throw new RuntimeException(
                'Invalid installed directory.'
            );
        }

        $current =
            rtrim(
                $stage,
                DIRECTORY_SEPARATOR
            );

        if ($relative === '') {
            return;
        }

        foreach (
            explode(
                DIRECTORY_SEPARATOR,
                $relative
            ) as $segment
        ) {
            if (
                $segment === '' ||
                $segment === '.' ||
                $segment === '..'
            ) {
                throw new RuntimeException(
                    'Invalid installed directory segment.'
                );
            }

            $current .=
                DIRECTORY_SEPARATOR .
                $segment;

            if (
                file_exists($current) ||
                is_link($current)
            ) {
                if (
                    !is_dir($current) ||
                    is_link($current)
                ) {
                    throw new RuntimeException(
                        'Unsafe installed directory.'
                    );
                }

                continue;
            }

            if (
                !mkdir(
                    $current,
                    0700,
                    false
                )
            ) {
                throw new RuntimeException(
                    'Unable to create installed directory.'
                );
            }

            chmod($current, 0700);
        }
    }

    private function createInstallationKeypair(
        string $stage
    ): void {
        $keypair =
            sodium_crypto_sign_keypair();

        $privateKey =
            sodium_crypto_sign_secretkey(
                $keypair
            );

        $publicKey =
            sodium_crypto_sign_publickey(
                $keypair
            );

        try {
            if (
                strlen($privateKey) !==
                    SODIUM_CRYPTO_SIGN_SECRETKEYBYTES ||
                strlen($publicKey) !==
                    SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES
            ) {
                throw new RuntimeException(
                    'Unable to generate installation keypair.'
                );
            }

            $privateFile =
                $stage .
                '/keys/installation.key';

            $publicFile =
                $stage .
                '/keys/installation.pub';

            $this->writeExclusiveFile(
                $privateFile,
                $privateKey,
                0600
            );

            $this->writeExclusiveFile(
                $publicFile,
                $publicKey,
                0600
            );

            $derived =
                sodium_crypto_sign_publickey_from_secretkey(
                    $privateKey
                );

            if (
                !hash_equals(
                    $publicKey,
                    $derived
                )
            ) {
                throw new RuntimeException(
                    'Installation keypair verification failed.'
                );
            }

            sodium_memzero($derived);

        } finally {
            sodium_memzero($privateKey);
            sodium_memzero($publicKey);
            sodium_memzero($keypair);
        }
    }

    private function writeDistributionMarker(
        string $stage,
        array $manifest
    ): void {
        $marker = [
            'schema' =>
                'ATLAS-CLIENT-INSTALLATION-V1',

            'distribution_version' =>
                $manifest[
                    'distribution_version'
                ],

            'application_version' =>
                self::APP_VERSION,

            'manifest_sha256' =>
                self::MANIFEST_SHA256,

            'domain' =>
                $this->domain,

            'installed_at' =>
                time(),
        ];

        try {
            $json =
                json_encode(
                    $marker,
                    JSON_THROW_ON_ERROR |
                    JSON_UNESCAPED_SLASHES
                );

        } catch (Throwable) {
            throw new RuntimeException(
                'Unable to encode installation marker.'
            );
        }

        if (!is_string($json)) {
            throw new RuntimeException(
                'Unable to encode installation marker.'
            );
        }

        $this->writeExclusiveFile(
            $stage .
                '/state/distribution.json',
            $json,
            0600
        );
    }

    private function writeExclusiveFile(
        string $file,
        string $content,
        int $mode
    ): void {
        if (
            file_exists($file) ||
            is_link($file)
        ) {
            throw new RuntimeException(
                'Private installation file already exists.'
            );
        }

        $handle =
            fopen(
                $file,
                'x+b'
            );

        if ($handle === false) {
            throw new RuntimeException(
                'Unable to create private installation file.'
            );
        }

        try {
            if (
                !flock(
                    $handle,
                    LOCK_EX
                ) ||
                fwrite(
                    $handle,
                    $content
                ) !== strlen($content) ||
                !fflush($handle)
            ) {
                throw new RuntimeException(
                    'Unable to write private installation file.'
                );
            }
        } finally {
            fclose($handle);
        }

        if (
            !chmod($file, $mode) ||
            filesize($file) !==
                strlen($content)
        ) {
            throw new RuntimeException(
                'Private installation file verification failed.'
            );
        }
    }

    private function activate(
        string $licenseKey
    ): array {
        $serviceRoot =
            $this->privateRoot .
            '/app/src/Service';

        require_once
            $this->privateRoot .
            '/app/src/Core/ClientPaths.php';

        require_once
            $this->privateRoot .
            '/app/src/Core/ClientConfig.php';

        require_once
            $serviceRoot .
            '/ClientLicenseTokenVerifier.php';

        require_once
            $serviceRoot .
            '/ClientActivationService.php';

        $config =
            \Atlas\Client\Core\ClientConfig::load(
                $this->privateRoot .
                '/config/client.php'
            );

        $verifier =
            new \Atlas\Client\Service\ClientLicenseTokenVerifier(
                $this->privateRoot .
                    '/trust/license-signing.pub',
                self::LICENSE_KEY_ID
            );

        $activation =
            new \Atlas\Client\Service\ClientActivationService(
                $this->privateRoot .
                    '/keys/installation.key',
                $this->privateRoot .
                    '/verification/domain-proof.json',
                $this->privateRoot .
                    '/state/license.token',
                $verifier,
                $config
            );

        $result =
            $activation->activate(
                $licenseKey,
                $this->domain,
                self::APP_VERSION
            );

        if (
            ($result['ok'] ?? false) !== true ||
            ($result['code'] ?? '') !==
                'ACTIVATED'
        ) {
            throw new RuntimeException(
                'Client activation failed.'
            );
        }

        require_once
            $serviceRoot .
            '/ClientIntegrationBootstrap.php';

        try {
            $maintenance =
                \Atlas\Client\Service\ClientIntegrationBootstrap::
                    runMaintenance(
                        self::APP_VERSION
                    );

            if (!is_array($maintenance)) {
                throw new RuntimeException(
                    'Invalid maintenance result.'
                );
            }

        } catch (Throwable $exception) {
            $fingerprint =
                hash(
                    'sha256',
                    get_class($exception) .
                    "\n" .
                    $exception->getMessage()
                );

            error_log(
                'Atlas post-activation maintenance [' .
                $fingerprint .
                '].'
            );
        }

        return $result;
    }

    private function removePrivateTree(
        string $directory
    ): void {
        $parent =
            realpath(
                dirname(
                    $this->privateRoot
                )
            );

        $directoryParent =
            realpath(
                dirname($directory)
            );

        if (
            $parent === false ||
            $directoryParent === false ||
            !hash_equals(
                $parent,
                $directoryParent
            ) ||
            !str_starts_with(
                basename($directory),
                '.atlas-client.install-'
            ) ||
            !is_dir($directory) ||
            is_link($directory)
        ) {
            return;
        }

        try {
            $iterator =
                new RecursiveIteratorIterator(
                    new RecursiveDirectoryIterator(
                        $directory,
                        FilesystemIterator::SKIP_DOTS
                    ),
                    RecursiveIteratorIterator::CHILD_FIRST
                );

            foreach ($iterator as $entry) {
                $path =
                    $entry->getPathname();

                if (
                    $entry->isLink() ||
                    $entry->isFile()
                ) {
                    @unlink($path);
                } elseif ($entry->isDir()) {
                    @rmdir($path);
                }
            }

            @rmdir($directory);

        } catch (Throwable) {
            /*
             * Cleanup failure must never replace the original exception.
             */
        }
    }

    private function render(
        int $status,
        string $title,
        string $message,
        bool $showForm
    ): never {
        http_response_code($status);

        header(
            'Content-Type: text/html; charset=UTF-8'
        );

        $safeTitle =
            htmlspecialchars(
                $title,
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            );

        $safeMessage =
            htmlspecialchars(
                $message,
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            );

        $form = '';

        if ($showForm) {
            $csrf =
                htmlspecialchars(
                    $this->csrf(),
                    ENT_QUOTES |
                    ENT_SUBSTITUTE,
                    'UTF-8'
                );

            $form =
                '<form method="post" autocomplete="off">' .
                '<input type="hidden" name="csrf_token" value="' .
                $csrf .
                '">' .
                '<label for="license_key">Atlas license key</label>' .
                '<input id="license_key" name="license_key" type="password" ' .
                'maxlength="60" spellcheck="false" autocomplete="off" required>' .
                '<button type="submit">Install and activate</button>' .
                '</form>';
        }

        echo '<!doctype html><html lang="en"><head>' .
            '<meta charset="utf-8">' .
            '<meta name="viewport" content="width=device-width,initial-scale=1">' .
            '<title>' . $safeTitle . '</title>' .
            '<style>' .
            ':root{color-scheme:dark}*{box-sizing:border-box}' .
            'body{margin:0;min-height:100vh;display:grid;place-items:center;' .
            'font-family:system-ui,-apple-system,Segoe UI,sans-serif;' .
            'background:#08111f;color:#eaf2ff;padding:24px}' .
            'main{width:min(100%,520px);background:#101c2f;border:1px solid #29415f;' .
            'border-radius:18px;padding:32px;box-shadow:0 24px 70px #0008}' .
            'h1{font-size:1.55rem;margin:0 0 14px}p{color:#b9c9dd;line-height:1.7}' .
            'form{display:grid;gap:12px;margin-top:24px}' .
            'label{font-weight:650}input{width:100%;padding:13px 14px;' .
            'border:1px solid #3a5576;border-radius:10px;background:#091525;' .
            'color:#fff;font:inherit}input:focus{outline:2px solid #4fa4ff}' .
            'button{padding:13px 16px;border:0;border-radius:10px;' .
            'background:#2388ef;color:white;font:inherit;font-weight:750;cursor:pointer}' .
            'button:hover{background:#1478dc}.brand{color:#63b3ff;font-weight:800}' .
            '</style></head><body><main>' .
            '<div class="brand">ATLAS</div>' .
            '<h1>' . $safeTitle . '</h1>' .
            '<p>' . $safeMessage . '</p>' .
            $form .
            '</main></body></html>';

        exit;
    }
}

$atlasInstallerScript =
    realpath(
        (string) (
            $_SERVER['SCRIPT_FILENAME']
            ?? ''
        )
    );

if (
    $atlasInstallerScript !== false &&
    hash_equals(
        __FILE__,
        $atlasInstallerScript
    )
) {
    try {
        (new AtlasWebInstaller())
            ->handle();

    } catch (Throwable $exception) {
        $fingerprint =
            hash(
                'sha256',
                get_class($exception) .
                "\n" .
                $exception->getMessage()
            );

        error_log(
            'Atlas installer bootstrap failure [' .
            $fingerprint .
            '].'
        );

        http_response_code(500);

        header(
            'Content-Type: text/html; charset=UTF-8'
        );

        echo '<!doctype html><html lang="en"><head>' .
            '<meta charset="utf-8"><title>Atlas installer</title>' .
            '</head><body><h1>Atlas installer unavailable</h1>' .
            '<p>Reference: ' .
            htmlspecialchars(
                substr($fingerprint, 0, 16),
                ENT_QUOTES |
                    ENT_SUBSTITUTE,
                'UTF-8'
            ) .
            '</p></body></html>';

        exit;
    }
}
