<?php

use App\Console\TickProvisioning;
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;

Artisan::command('inspire', function () {
    $this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');

// Advance every due provisioning run once a minute (runs in the scheduler service).
Schedule::call(fn () => app(TickProvisioning::class)())
    ->everyMinute()
    ->name('provisioning-tick')
    ->withoutOverlapping();

// Refresh the VPN peer state (handshakes, traffic) so the console does not go
// stale while nobody has it open. The job itself runs on the provisioning
// queue — that worker owns wg0.
Schedule::job(new \App\Provisioning\Jobs\SyncVpnPeers)
    ->everyMinute()
    ->name('vpn-sync');

// Sample network counters and enforce the monthly allowance. Runs on the
// provisioning queue, which is where the Proxmox credentials are usable.
// Turns the monitoring column from a claim into a measurement. Without it the
// console and the public status page report every instance healthy forever.
Schedule::job(new \App\Provisioning\Jobs\SyncMonitoringStatus)
    ->everyFiveMinutes()
    ->withoutOverlapping();

Schedule::job(new \App\Provisioning\Jobs\CollectInstanceTraffic)
    ->everyFifteenMinutes()
    ->name('traffic-collect');

// Discard Stripe events that were held for a contract which never appeared.
// Most of them never will: Stripe also delivers events for subscriptions
// belonging to other environments pointed at this endpoint, and for objects
// made by hand in the dashboard. A week is far longer than the moment a
// checkout takes to become a contract, and short enough that the table stays
// a holding area rather than a second copy of Stripe's event log.
Schedule::call(fn () => \App\Models\StripePendingEvent::query()
    ->where('created_at', '<', now()->subWeek())
    ->delete())
    ->daily()
    ->name('stripe-pending-prune');

// Copies of invoices that never reached the archive — a NAS that was rebooting
// when the invoice was issued, a mount that had gone away. Copy-on-issue is
// right and is not enough: nobody opens an archive to check whether last
// Tuesday is in it, so something has to go and look.
//
// Hourly rather than by the minute: the failure it repairs lasts as long as an
// outage lasts, and a retry storm against a mount that is down helps nobody.
Schedule::command('clupilot:archive-invoices')
    ->hourly()
    ->withoutOverlapping();

// Empty a handover directory of folders past their keep-by. Only where a
// destination asks for it, and only folders whose name is a date this
// application wrote — see the command for why it leaves everything else alone.
Schedule::command('clupilot:prune-exports')
    ->dailyAt('03:20')
    ->withoutOverlapping();

// One sample of every public status component, into today's row.
//
// The ninety-day bar on the status page is the one figure a reader checks
// against their own memory, so it has to come from something recorded at the
// time — there is no way to reconstruct it later. Beside the monitoring sync it
// reads from, at the same cadence.
Schedule::command('clupilot:sample-status')
    ->everyFiveMinutes()
    ->withoutOverlapping();

// Re-read the DNS proof for every custom domain.
//
// Not a one-off: a token checked once can be taken straight back out, and a
// domain that later lapses and is registered by somebody else keeps resolving
// to the same instance. Nightly, and at an hour where withdrawing a domain
// inconveniences nobody — a withdrawal takes a working Nextcloud off its own
// address, which is not a thing to do at eleven in the morning.
Schedule::command('clupilot:verify-domains')
    ->dailyAt('03:40')
    ->withoutOverlapping();

// Take an available release inside the configured window, if the owner has
// switched that on. Every five minutes rather than once at the start of the
// window: a scheduler that was down for those sixty seconds would otherwise
// skip the whole night.
Schedule::command('clupilot:auto-update')
    ->everyFiveMinutes()
    ->withoutOverlapping();

// Ask every host whether it is still there.
//
// hosts.last_seen_at drove the console's health dot and was written exactly
// once, at onboarding — so every host read "offline" half an hour later,
// permanently. Nothing was measuring host reachability at all, which is also
// why it could not appear on the status page.
Schedule::job(new \App\Provisioning\Jobs\PingHosts)
    ->everyMinute()
    ->name('host-ping');
