<?php
declare(strict_types=1);

namespace Wohno\Plugin\Cron;

use Wohno\Plugin\Api\Client;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * WP-Cron wiring for the background cache prewarm.
 *
 * Registers a 5-minute schedule, ensures the recurring prewarm event exists,
 * and binds both cron hooks to the {@see Client}. This is what keeps the
 * front-end render off the network: cron refreshes known queries ahead of time,
 * and stale renders enqueue a one-off refresh.
 */
final class Scheduler {

	/**
	 * Constructor.
	 *
	 * @param Client $client Shared API client.
	 */
	public function __construct( private readonly Client $client ) {
	}

	/**
	 * Register cron schedule, scheduling guard and hook handlers.
	 *
	 * @return void
	 */
	public function register(): void {
		// 5-min interval is intentional (cheap ETag-validated prewarm, see add_interval()).
		add_filter( 'cron_schedules', array( $this, 'add_interval' ) ); // phpcs:ignore WordPress.WP.CronInterval.CronSchedulesInterval
		add_action( 'init', array( $this, 'ensure_scheduled' ) );
		add_action( Client::PREWARM_HOOK, array( $this->client, 'prewarm_all' ) );
		add_action( Client::REFRESH_HOOK, array( $this->client, 'refresh_event' ), 10, 1 );
		add_action( Client::REFRESH_ONE_HOOK, array( $this->client, 'refresh_one_event' ), 10, 1 );
	}

	/**
	 * Add the custom 5-minute schedule.
	 *
	 * @param array<string, array{interval: int, display: string}> $schedules Existing schedules.
	 * @return array<string, array{interval: int, display: string}>
	 */
	public function add_interval( array $schedules ): array {
		// 5 min is intentional: it keeps rendered queries warm so the front-end
		// never blocks on the API. The job is a cheap ETag-validated refresh
		// (304 = no quota cost), not heavy work.
		$schedules[ Client::CRON_SCHEDULE ] = array(
			'interval' => 5 * MINUTE_IN_SECONDS,
			'display'  => __( 'Alle 5 Minuten (Wohno)', 'wohno' ),
		);

		return $schedules;
	}

	/**
	 * Ensure the recurring prewarm event is scheduled exactly once.
	 *
	 * @return void
	 */
	public function ensure_scheduled(): void {
		if ( false === wp_next_scheduled( Client::PREWARM_HOOK ) ) {
			wp_schedule_event( time() + MINUTE_IN_SECONDS, Client::CRON_SCHEDULE, Client::PREWARM_HOOK );
		}
	}

	/**
	 * Remove the recurring prewarm event. Called on plugin deactivation.
	 *
	 * @return void
	 */
	public static function clear(): void {
		wp_clear_scheduled_hook( Client::PREWARM_HOOK );
		wp_clear_scheduled_hook( Client::REFRESH_HOOK );
		wp_clear_scheduled_hook( Client::REFRESH_ONE_HOOK );
	}
}
