<?php

namespace App\Provisioning\Steps\Customer;

use App\Models\ProvisioningRun;
use App\Provisioning\StepResult;
use App\Services\Proxmox\ProxmoxClient;

class ConfigureNetwork extends CustomerStep
{
    public function __construct(private ProxmoxClient $pve) {}

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

    public function maxDuration(): int
    {
        // Above the 90s guest-ip own-deadline below.
        return 150;
    }

    public function execute(ProvisioningRun $run): StepResult
    {
        $instance = $this->instance($run);
        $node = (string) $run->context('node');
        $vmid = (int) $run->context('vmid');
        $pve = $this->pve->forHost($instance->host);

        $this->guest($pve, $run, 'hostnamectl set-hostname '.escapeshellarg($instance->subdomain));

        // Capture the guest's own address so Traefik routes to the VM, not the
        // host. Poll until it's available rather than advancing with no address.
        $ipOut = trim($pve->guestExec($node, $vmid, 'hostname -I')['out-data'] ?? '');
        $guestIp = trim(strtok($ipOut, ' ') ?: '');
        if ($guestIp === '') {
            if ($run->started_at !== null && $run->started_at->copy()->addSeconds(90)->isPast()) {
                return StepResult::fail('guest_ip_unavailable');
            }

            return StepResult::poll(10, 'waiting for the guest to obtain an address');
        }
        $instance->update(['guest_ip' => $guestIp]);

        // Allow HTTP/HTTPS, deny everything else (management stays on the tunnel).
        $pve->applyFirewall($node, $vmid, [
            ['type' => 'in', 'action' => 'ACCEPT', 'proto' => 'tcp', 'dport' => '80'],
            ['type' => 'in', 'action' => 'ACCEPT', 'proto' => 'tcp', 'dport' => '443'],
        ]);

        return StepResult::advance();
    }
}
