<?php

namespace App\Services;

use App\Models\Server;
use Illuminate\Support\Collection;
use Throwable;

/**
 * Runs one (arbitrary, user-supplied) command across a set of servers and collects a per-server
 * result. The command is INTENTIONALLY arbitrary — it runs via FleetService::runPlain (the
 * credential's login user, base64 transport, no extra sudo) exactly as the web terminal would.
 * One server failing (connect/exec) never aborts the batch. Remote output is byte-capped +
 * mb_scrub'd so it can safely land in a Livewire property.
 */
class CommandRunner
{
    private const MAX_BYTES = 262144; // 256 KiB per server

    public function __construct(private FleetService $fleet) {}

    /**
     * @param  Collection<int, Server>  $servers
     * @return array<int, array{server:string, ok:bool, output:string}>
     */
    public function run(string $command, Collection $servers, int $timeout = 60): array
    {
        $results = [];

        foreach ($servers as $server) {
            try {
                $res = $this->fleet->runPlain($server, $command, $timeout);
                $results[] = ['server' => $server->name, 'ok' => (bool) $res['ok'], 'output' => $this->clean($res['output'])];
            } catch (Throwable $e) {
                $results[] = ['server' => $server->name, 'ok' => false, 'output' => $this->clean($e->getMessage())];
            }
        }

        return $results;
    }

    private function clean(string $output): string
    {
        return mb_scrub(mb_strcut($output, 0, self::MAX_BYTES), 'UTF-8');
    }
}
