<?php
/**
 * `wp powersuite cron` commands.
 *
 * @package WP_PowerSuite\CLI
 * @since 1.0.7
 */

namespace WP_PowerSuite\CLI;

use WP_PowerSuite\CLI\Support\Cli;
use WP_PowerSuite\Core\DataRegistry;

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

/**
 * Inspect and run WP PowerSuite-owned scheduled tasks.
 *
 * Only hooks owned by WP PowerSuite are listed or runnable — arbitrary WP-Cron
 * hooks are never touched from this command.
 *
 * @since 1.0.7
 */
final class CronCommand {

	/**
	 * List WP PowerSuite scheduled tasks and their next run time.
	 *
	 * ## OPTIONS
	 *
	 * [--format=<format>]
	 * : Render output in a particular format.
	 * ---
	 * default: table
	 * options:
	 *   - table
	 *   - csv
	 *   - json
	 *   - yaml
	 *   - count
	 * ---
	 *
	 * ## EXAMPLES
	 *
	 *     $ wp powersuite cron list
	 *
	 * @subcommand list
	 * @when after_wp_load
	 *
	 * @param array<int, string>   $args       Positional arguments (unused).
	 * @param array<string, mixed> $assoc_args Associative arguments.
	 * @return void
	 */
	public function list_( array $args, array $assoc_args ): void {
		$rows = [];
		foreach ( $this->ownedHooks() as $hook ) {
			$next = wp_next_scheduled( $hook );
			$rows[] = [
				'hook'      => $hook,
				'scheduled' => $next ? 'yes' : 'no',
				'next_run'  => $next ? gmdate( 'Y-m-d H:i:s', (int) $next ) . ' UTC' : '—',
				'recurrence'=> $next ? $this->recurrence( $hook ) : '—',
			];
		}

		$format = Cli::format( $assoc_args, [ 'table', 'csv', 'json', 'yaml', 'count' ], 'table' );
		\WP_CLI\Utils\format_items( $format, $rows, [ 'hook', 'scheduled', 'next_run', 'recurrence' ] );
	}

	/**
	 * Run a WP PowerSuite scheduled task now.
	 *
	 * Only hooks owned by WP PowerSuite may be run. The hook's registered
	 * callbacks are executed immediately in this process.
	 *
	 * ## OPTIONS
	 *
	 * <hook>
	 * : The cron hook name to run (see `wp powersuite cron list`).
	 *
	 * ## EXAMPLES
	 *
	 *     $ wp powersuite cron run wpps_activity_log_cleanup
	 *
	 * @when after_wp_load
	 *
	 * @param array<int, string>   $args       Positional arguments.
	 * @param array<string, mixed> $assoc_args Associative arguments.
	 * @return void
	 */
	public function run( array $args, array $assoc_args ): void {
		$hook = isset( $args[0] ) ? (string) $args[0] : '';
		if ( $hook === '' ) {
			\WP_CLI::error( __( 'Provide a cron hook name. See: wp powersuite cron list', 'wp-powersuite' ) );
		}

		if ( ! in_array( $hook, $this->ownedHooks(), true ) ) {
			\WP_CLI::error(
				sprintf(
					/* translators: %s: hook name */
					__( 'Not a WP PowerSuite cron hook: %s', 'wp-powersuite' ),
					$hook
				)
			);
		}

		if ( ! has_action( $hook ) ) {
			\WP_CLI::warning(
				sprintf(
					/* translators: %s: hook name */
					__( 'No callbacks are registered for %s in this context (the owning module may be disabled). Nothing to run.', 'wp-powersuite' ),
					$hook
				)
			);
			return;
		}

		/* translators: %s: string value. */
		\WP_CLI::log( sprintf( __( 'Running %s...', 'wp-powersuite' ), $hook ) );
		do_action( $hook );

		\WP_CLI::success(
			sprintf(
				/* translators: %s: hook name */
				__( 'Ran %s.', 'wp-powersuite' ),
				$hook
			)
		);
	}

	/**
	 * Union of module-owned and core-owned cron hooks.
	 *
	 * @return list<string>
	 */
	private function ownedHooks(): array {
		$hooks = array_merge( DataRegistry::getCronHooks(), DataRegistry::getCoreCronHooks() );
		$hooks = array_values( array_unique( array_filter( array_map( 'strval', $hooks ) ) ) );
		sort( $hooks );
		return $hooks;
	}

	/**
	 * Resolve the recurrence schedule slug for a scheduled hook.
	 *
	 * @param string $hook Hook name.
	 * @return string
	 */
	private function recurrence( string $hook ): string {
		$schedule = wp_get_schedule( $hook );
		return is_string( $schedule ) && $schedule !== '' ? $schedule : 'single';
	}
}

