<?php

namespace App\Actions;

use App\Models\Host;
use App\Models\ProvisioningRun;
use App\Provisioning\Jobs\AdvanceRunJob;
use App\Support\HostName;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;

/**
 * Registers a fresh host and kicks off its onboarding run. The one-time root
 * password lives encrypted in the run context and is scrubbed after SSH trust
 * is established.
 */
class StartHostOnboarding
{
    /**
     * @param  array{datacenter: string, public_ip: string, root_password: string}  $input
     */
    public function run(array $input): Host
    {
        // Host + run are created atomically; a partial insert would otherwise
        // leave a permanently pending host with no run.
        [$host, $run] = DB::transaction(function () use ($input) {
            $host = Host::create([
                // Den Namen vergibt CluPilot, nicht der Betreiber. Innerhalb
                // DIESER Transaktion, weil HostName::claim die
                // Rechenzentrums-Zeile sperrt und die Sperre nur bis zu deren
                // Ende hält — außerhalb bekämen zwei gleichzeitige
                // Anlegen-Vorgänge dieselbe Nummer.
                'name' => HostName::claim($input['datacenter']),
                'datacenter' => $input['datacenter'],
                'public_ip' => $input['public_ip'],
                'status' => 'pending',
            ]);

            $run = ProvisioningRun::create([
                'subject_type' => Host::class,
                'subject_id' => $host->id,
                'pipeline' => 'host',
                'status' => ProvisioningRun::STATUS_PENDING,
                'current_step' => 0,
                'context' => ['root_password' => Crypt::encryptString($input['root_password'])],
            ]);

            return [$host, $run];
        });

        AdvanceRunJob::dispatch($run->uuid); // after commit — the run definitely exists

        return $host;
    }
}
