<?php

namespace App\Support\Readiness;

use App\Models\Host;
use App\Models\PlanVersion;
use App\Services\Secrets\SecretVault;
use App\Support\ProvisioningSettings;

/**
 * What has to be in place for a PAID order to actually turn into a running,
 * reachable machine: somewhere to put it, a name for it, and a router that
 * knows about it.
 */
final class ProvisioningChecks
{
    public const GROUP = 'provisioning';

    /** @return array<int, Check> */
    public static function all(): array
    {
        return [
            new Check(
                key: 'provisioning.dns_token',
                group: self::GROUP,
                severity: Check::SEVERITY_BLOCKING,
                label: __('readiness.provisioning.dns_token'),
                breaks: __('readiness.provisioning.dns_token_breaks'),
                // The DNS card (token + zone + Traefik path) is on the
                // 'services' tab — 'integrations' is not a member of
                // Integrations::TABS at all (Fix-Runde, Befund 1).
                tab: 'services',
                satisfied: filled(app(SecretVault::class)->get('dns.token')),
            ),
            new Check(
                key: 'provisioning.dns_zone',
                group: self::GROUP,
                severity: Check::SEVERITY_BLOCKING,
                label: __('readiness.provisioning.dns_zone'),
                breaks: __('readiness.provisioning.dns_zone_breaks'),
                // Same DNS card as provisioning.dns_token just above.
                tab: 'services',
                satisfied: filled(ProvisioningSettings::dnsZone()),
            ),
            new Check(
                key: 'provisioning.traefik_path',
                group: self::GROUP,
                severity: Check::SEVERITY_WARNING,
                label: __('readiness.provisioning.traefik_path'),
                breaks: __('readiness.provisioning.traefik_path_breaks'),
                // Same DNS card — traefikDynamicPath is a field on it.
                tab: 'services',
                satisfied: filled(ProvisioningSettings::traefikDynamicPath()),
            ),
            new Check(
                key: 'provisioning.usable_host',
                group: self::GROUP,
                severity: Check::SEVERITY_BLOCKING,
                label: __('readiness.provisioning.usable_host'),
                breaks: __('readiness.provisioning.usable_host_breaks'),
                tab: 'hosts',
                // `active` ALONE is not enough. A host without a readable
                // token is still selectable to ReserveResources, and the
                // order then dies in CloneVirtualMachine — after payment.
                satisfied: Host::query()
                    ->where('status', 'active')
                    ->whereNotNull('api_token_ref')
                    ->exists(),
            ),
            new Check(
                key: 'provisioning.vm_template',
                group: self::GROUP,
                severity: Check::SEVERITY_BLOCKING,
                label: __('readiness.provisioning.vm_template'),
                breaks: __('readiness.provisioning.vm_template_breaks'),
                tab: 'plans',
                // A field check only. Whether the template actually EXISTS on
                // a node is answered by the button in Task 9 — that has to
                // ask Proxmox, and a live API call does not belong on every
                // page load of this readiness page.
                satisfied: PlanVersion::query()
                    ->whereNotNull('published_at')
                    ->whereNull('template_vmid')
                    ->doesntExist(),
            ),
            new Check(
                key: 'provisioning.monitoring_token',
                group: self::GROUP,
                // Follows the same condition RegisterMonitoring itself reads
                // (RegisterMonitoring.php: `if (config('provisioning.
                // monitoring.required', false)) { throw $e; }`). Warning by
                // default — monitoring degrades, then the run continues — but
                // an operator who has switched that setting on made
                // monitoring a real gate, and a fixed severity would then
                // claim a looser rule than the pipeline actually enforces.
                severity: config('provisioning.monitoring.required', false)
                    ? Check::SEVERITY_BLOCKING
                    : Check::SEVERITY_WARNING,
                label: __('readiness.provisioning.monitoring_token'),
                breaks: __('readiness.provisioning.monitoring_token_breaks'),
                // The monitoring card is on the 'services' tab too.
                tab: 'services',
                satisfied: filled(app(SecretVault::class)->get('monitoring.token')),
            ),
        ];
    }
}
