<?php
declare(strict_types=1);

/** Ephemeral reverse-SSH session credentials (alpha). */
final class RsshSessionProvisioner {
    private function __construct() {
    }

    /** @return array{bastion_host:string,bastion_port:int,username:string,password:string,remote_bind_port:int,local_forward_port:int} */
    public static function allocate(string $sessionId): array {
        $host = (string) cfg('remote_access.rssh.bastion_host', 'ra.apps.f0xx.org');
        $port = max(1, min(65535, (int) cfg('remote_access.rssh.bastion_port', 443)));
        $prefix = (string) cfg('remote_access.rssh.username_prefix', 'ra-');
        $username = $prefix . preg_replace('/[^a-zA-Z0-9_-]/', '', $sessionId);
        if (strlen($username) > 32) {
            $username = substr($username, 0, 32);
        }
        $password = bin2hex(random_bytes(16));
        $remotePort = self::allocateRemotePort($sessionId);
        $localPort = max(1, min(65535, (int) cfg('remote_access.rssh.local_forward_port', 8022)));
        return [
            'bastion_host' => $host,
            'bastion_port' => $port,
            'username' => $username,
            'password' => $password,
            'remote_bind_port' => $remotePort,
            'local_forward_port' => $localPort,
        ];
    }

    public static function allocateRemotePort(string $sessionId): int {
        $min = (int) cfg('remote_access.rssh.remote_port_min', 18000);
        $max = (int) cfg('remote_access.rssh.remote_port_max', 18999);
        if ($max <= $min) {
            $max = $min + 999;
        }
        $span = $max - $min + 1;
        return $min + (abs(crc32($sessionId . '|' . time())) % $span);
    }

    /** @param array<string, mixed> $session */
    public static function endpointFromSession(array $session): string {
        $host = (string) ($session['rssh_bastion_host'] ?? cfg('remote_access.rssh.bastion_host', 'ra.apps.f0xx.org'));
        $port = (int) ($session['rssh_bastion_port'] ?? cfg('remote_access.rssh.bastion_port', 443));
        if ($port === 443) {
            return $host;
        }
        return $host . ':' . $port;
    }
}
