<?php
declare(strict_types=1);

/** Ephemeral Linux users on the RSSH bastion (sshd Match User ra-*). */
final class RsshBastionProvisioner {
    private function __construct() {
    }

    public static function isEnabled(): bool {
        return (bool) cfg('remote_access.rssh.provision_users', false);
    }

    public static function scriptPath(): string {
        $configured = trim((string) cfg('remote_access.rssh.provision_script', ''));
        if ($configured !== '') {
            return $configured;
        }
        return dirname(__DIR__) . '/scripts/rssh_bastion_user.sh';
    }

    /** @return array{ok:bool,error?:string} */
    public static function addUser(string $username, string $password): array {
        $user = self::normalizeUsername($username);
        if ($user === '') {
            return ['ok' => false, 'error' => 'invalid_username'];
        }
        if (!self::isEnabled()) {
            return ['ok' => true];
        }
        $code = self::runScript('add', $user, $password);
        if ($code !== 0) {
            error_log('RsshBastionProvisioner add failed for ' . $user . ' exit=' . $code);
            return ['ok' => false, 'error' => 'bastion_user_add_failed'];
        }
        return ['ok' => true];
    }

    public static function removeUser(?string $username): void {
        $user = self::normalizeUsername((string) $username);
        if ($user === '' || !self::isEnabled()) {
            return;
        }
        $code = self::runScript('remove', $user, '');
        if ($code !== 0) {
            error_log('RsshBastionProvisioner remove failed for ' . $user . ' exit=' . $code);
        }
    }

    /** Operator command lines once device has connected reverse forward. */
    public static function operatorCommands(array $session): array {
        $username = trim((string) ($session['rssh_username'] ?? ''));
        $remotePort = (int) ($session['rssh_remote_port'] ?? 0);
        if ($username === '' || $remotePort <= 0) {
            return [];
        }
        $host = '127.0.0.1';
        return [
            'shell' => sprintf('ssh -p %d %s@%s', $remotePort, $username, $host),
            'sftp' => sprintf('sftp -P %d %s@%s', $remotePort, $username, $host),
            'scp_example' => sprintf('scp -P %d %s@%s:/path/on/device ./', $remotePort, $username, $host),
        ];
    }

    private static function normalizeUsername(string $username): string {
        $user = trim($username);
        if ($user === '' || !preg_match('/^ra-[a-zA-Z0-9_-]{1,30}$/', $user)) {
            return '';
        }
        return $user;
    }

    private static function runScript(string $action, string $username, string $password): int {
        $script = self::scriptPath();
        if (!is_file($script) || !is_executable($script)) {
            error_log('RsshBastionProvisioner: script missing or not executable: ' . $script);
            return 127;
        }
        $cmd = escapeshellarg($script) . ' ' . escapeshellarg($action) . ' ' . escapeshellarg($username);
        if ($action === 'add') {
            $cmd .= ' ' . escapeshellarg($password);
        }
        $out = [];
        exec($cmd . ' 2>&1', $out, $code);
        if ($code !== 0 && $out !== []) {
            error_log('RsshBastionProvisioner: ' . implode("\n", $out));
        }
        return (int) $code;
    }
}
