<?php

namespace App\Provisioning\Steps\Customer;

use App\Models\ProvisioningRun;
use App\Provisioning\StepResult;
use App\Services\Billing\StorageAllowance;
use App\Services\Proxmox\ProxmoxClient;
use App\Support\NextcloudOcc;

/**
 * The storage a plan change actually delivers.
 *
 * This is the half of a plan change that a downgrade can carry out in full: a
 * disk cannot be shrunk, but a quota can, and the quota is what was sold. The
 * customer on a 200 GB package gets 200 GB whatever size the underlying disk
 * happens to be, and Nextcloud is what enforces it.
 *
 * What is written is the customer's whole allowance — the package PLUS every
 * storage pack booked onto their contract — and it is asked of
 * StorageAllowance rather than read off `instances.quota_gb`. That column is the
 * package alone, and taking it as the answer is how a booked pack came to change
 * nothing at all: the customer paid ten euros a month and Nextcloud went on
 * enforcing the figure the package included.
 *
 * `files default_quota`, not a per-user quota. An account with an explicit quota
 * stops following the default, so writing one onto the admin account would
 * freeze that account at today's figure and quietly exclude it from the next
 * plan change. The default applies to every account on the instance — which is
 * what a package's storage allowance means here, since a package is a whole
 * Nextcloud and not a seat on a shared one.
 */
class ApplyStorageQuota extends CustomerStep
{
    public function __construct(private ProxmoxClient $pve) {}

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

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

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

        if ($instance === null) {
            return StepResult::fail('no_instance');
        }

        $quota = StorageAllowance::for($instance)->totalGb();

        // No allowance recorded: setting "0 GB" would lock the customer out of
        // their own files, which is a far worse answer than leaving what is
        // there and letting somebody notice.
        if ($quota <= 0) {
            return StepResult::advance();
        }

        $pve = $this->pve->forHost($instance->host);

        // Idempotent, like every other occ call in this pipeline: writing the
        // same value again is a no-op and exits 0.
        $this->guest($pve, $run, NextcloudOcc::command('config:app:set files default_quota --value='.escapeshellarg($quota.' GB')));

        // Recorded only AFTER the guest accepted it — guest() throws on a
        // non-zero exit, so nothing below runs for a call that failed. Without
        // this line there is no way to tell a machine whose allowance is
        // enforced from one where the figure has only ever been a row in our
        // database, which is precisely how every instance built before this step
        // existed came to have the whole disk. See clupilot:apply-quotas.
        $instance->update(['quota_applied_gb' => $quota]);

        return StepResult::advance();
    }
}
