<?php
/**
 * Task Scheduler Wrapper.
 *
 * @package automation-web-platform
 */

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

/**
 * WAWP Task Scheduler
 * A wrapper for Action Scheduler with a fallback to WP-Cron.
 */
class WAWP_Task_Scheduler {

	/**
	 * Schedule a recurring action.
	 *
	 * @param int    $timestamp           Start timestamp.
	 * @param int    $interval_in_seconds Interval in seconds.
	 * @param string $hook                The hook to trigger.
	 * @param array  $args                Arguments for the hook.
	 * @param string $group               The group name (default: wawp).
	 */
	public static function schedule_recurring( $timestamp, $interval_in_seconds, $hook, $args = array(), $group = 'wawp' ) {

		// Use Action Scheduler if available and initialized.
		if ( function_exists( 'as_schedule_recurring_action' ) && class_exists( 'ActionScheduler' ) && ActionScheduler::is_initialized() ) {
			// Prevent duplicates in Action Scheduler.
			if ( ! self::next_scheduled( $hook, $args, $group ) ) {
				as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook, $args, $group );

				// Migration: Clear from WP Cron if it was there.
				wp_clear_scheduled_hook( $hook, $args );
			}
		} else {
			// Fallback to WP Cron
			// If Action Scheduler is present but not yet initialized, we wait for the 'init' hook.
			if ( class_exists( 'ActionScheduler' ) && ! ActionScheduler::is_initialized() ) {
				// We don't schedule in WP-Cron if AS is intended to be used but just not ready yet.
				return;
			}

			if ( ! wp_next_scheduled( $hook, $args ) ) {
				$wp_interval = self::seconds_to_cron_interval( $interval_in_seconds );
				wp_schedule_event( $timestamp, $wp_interval, $hook, $args );
			}
		}
	}

	/**
	 * Schedule a single action.
	 *
	 * @param int    $timestamp Release timestamp.
	 * @param string $hook      The hook to trigger.
	 * @param array  $args      Arguments for the hook.
	 * @param string $group     The group name (default: wawp).
	 */
	public static function schedule_single( $timestamp, $hook, $args = array(), $group = 'wawp' ) {
		if ( function_exists( 'as_schedule_single_action' ) ) {
			as_schedule_single_action( $timestamp, $hook, $args, $group );

			// Migration/Cleanup: Clear from WP Cron.
			wp_unschedule_event( $timestamp, $hook, $args );
		} else {
			wp_schedule_single_event( $timestamp, $hook, $args );
		}
	}

	/**
	 * Unschedule an action.
	 *
	 * @param string $hook  The hook to unschedule.
	 * @param array  $args  Arguments to match.
	 * @param string $group The group name (default: wawp).
	 */
	public static function unschedule_all( $hook, $args = array(), $group = 'wawp' ) {
		if ( function_exists( 'as_unschedule_all_actions' ) ) {
			as_unschedule_all_actions( $hook, $args, $group );
		}
		wp_clear_scheduled_hook( $hook, $args );
	}

	/**
	 * Unschedule a specific action instance by timestamp.
	 *
	 * @param int    $timestamp Timestamp of the action.
	 * @param string $hook      The hook to unschedule.
	 * @param array  $args      Arguments to match.
	 * @param string $group     The group name (default: wawp).
	 */
	public static function unschedule_at( $timestamp, $hook, $args = array(), $group = 'wawp' ) {
		if ( function_exists( 'as_unschedule_action' ) ) {
			as_unschedule_action( $hook, $args, $group );
		}
		wp_unschedule_event( $timestamp, $hook, $args );
	}

	/**
	 * Get the next scheduled timestamp for an action.
	 *
	 * @param string $hook  The hook name.
	 * @param array  $args  Arguments to match.
	 * @param string $group The group name (default: wawp).
	 * @return int|false Timestamp or false if not scheduled.
	 */
	public static function next_scheduled( $hook, $args = array(), $group = 'wawp' ) {
		static $runtime_cache = array();
		$cache_key            = md5( $hook . wp_json_encode( $args ) . $group );

		if ( isset( $runtime_cache[ $cache_key ] ) ) {
			return $runtime_cache[ $cache_key ];
		}

		$as_next = false;
		if ( function_exists( 'as_next_scheduled_action' ) ) {
			$as_next = as_next_scheduled_action( $hook, $args, $group );
		}

		$wp_next = wp_next_scheduled( $hook, $args );

		if ( $as_next && $wp_next ) {
			$res = min( $as_next, $wp_next );
		} else {
			$res = $as_next ? $as_next : $wp_next;
		}

		$runtime_cache[ $cache_key ] = $res;
		return $res;
	}

	/**
	 * Map seconds to WP-Cron standard intervals.
	 *
	 * @param int $seconds Seconds.
	 * @return string Interval.
	 */
	private static function seconds_to_cron_interval( $seconds ) {
		if ( $seconds <= 300 ) {
			return 'five_minutes';
		}

		if ( $seconds <= 3600 ) {
			return 'hourly';
		}

		if ( $seconds <= 43200 ) {
			return 'twelve_hours';
		}

		return 'daily';
	}
}
