<?php

namespace App\Provisioning\Steps\Customer;

use App\Models\ProvisioningRun;
use App\Provisioning\StepResult;
use App\Services\Proxmox\ProxmoxClient;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;

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

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

    public function maxDuration(): int
    {
        return 1200;
    }

    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);

        // Deploy once (guarded). The DB password is persisted ENCRYPTED before the
        // stack starts and reused on retry, so a crash before `stack_deployed`
        // can't regenerate a password that mismatches the initialized database.
        if (! $run->context('stack_deployed')) {
            $encrypted = $run->context('db_password');
            $dbPassword = $encrypted !== null ? Crypt::decryptString($encrypted) : Str::random(28);
            if ($encrypted === null) {
                $run->mergeContext(['db_password' => Crypt::encryptString($dbPassword)]);
            }

            $this->guest($pve, $run,
                'install -d /opt/nextcloud && printf %s '.escapeshellarg('MYSQL_PASSWORD='.$dbPassword."\n").
                ' > /opt/nextcloud/.env');
            $this->guest($pve, $run, 'cd /opt/nextcloud && docker compose up -d');

            $run->mergeContext(['stack_deployed' => true]);
        }

        // Poll until Nextcloud answers (poll doesn't consume the retry budget).
        $health = $pve->guestExec($node, $vmid,
            'curl -sf http://localhost/status.php >/dev/null 2>&1 && echo ok || echo wait');
        if (trim($health['out-data'] ?? '') !== 'ok') {
            return StepResult::poll(15, 'waiting for application stack');
        }

        $run->forgetContext('db_password'); // scrub once the stack is up

        return StepResult::advance();
    }
}
