<?php

namespace App\Provisioning\Steps\Host;

use App\Models\ProvisioningRun;
use App\Provisioning\StepResult;
use App\Services\Ssh\RemoteShell;
use Illuminate\Support\Carbon;
use Throwable;

/**
 * Removes the Debian kernel and reboots into the Proxmox kernel. The reboot is
 * modelled as a retry loop: issue once, then poll until `uname -r` reports a
 * -pve kernel. The state machine survives the reboot by design.
 */
class RebootIntoPveKernel extends HostStep
{
    public function __construct(private RemoteShell $shell) {}

    public function key(): string
    {
        return 'reboot_into_pve_kernel';
    }

    public function maxDuration(): int
    {
        // Above the 15-min reboot deadline below, so the step's own deadline
        // governs failure rather than the generic step timeout.
        return 1800;
    }

    public function execute(ProvisioningRun $run): StepResult
    {
        $host = $this->host($run);

        if (! $run->context('reboot_issued')) {
            $this->keyLogin($this->shell, $host);
            $this->shell->run('export DEBIAN_FRONTEND=noninteractive; apt-get -y remove linux-image-amd64 || true');
            $this->shell->run('update-grub');
            $run->mergeContext([
                'reboot_issued' => true,
                'reboot_deadline' => now()->addMinutes(15)->toIso8601String(),
            ]);
            $this->shell->run('systemctl reboot || reboot');

            return StepResult::poll(30, 'rebooting into the Proxmox kernel');
        }

        try {
            $this->keyLogin($this->shell, $host);
            $uname = trim($this->shell->run('uname -r')->stdout);
        } catch (Throwable) {
            $uname = '';
        }

        if (str_contains($uname, '-pve')) {
            return StepResult::advance();
        }

        $deadline = $run->context('reboot_deadline');
        if ($deadline !== null && now()->greaterThan(Carbon::parse($deadline))) {
            // Clear the reboot markers so a manual retry re-issues a fresh reboot
            // instead of immediately re-hitting the expired deadline.
            $run->forgetContext('reboot_issued');
            $run->forgetContext('reboot_deadline');

            return StepResult::fail('Host did not return on the Proxmox kernel before the deadline.');
        }

        return StepResult::poll(15, 'waiting for the Proxmox kernel');
    }
}
