<?php
/**
 * Detects overdue timed automation hooks and throttles fallback runner dispatch.
 *
 * @package Niwa_AI
 */

defined( 'ABSPATH' ) || exit;

class Niwa_AI_Admin_Autonomy_Timed_Automation_Fallback {
	/** @var string */
	private $state_option;

	/** @var array<int,string> */
	private $hooks;

	/** @var int */
	private $min_interval;

	/** @var array<string,callable> */
	private $callbacks;

	public function __construct( $state_option, $hooks, $min_interval, $callbacks = array() ) {
		$this->state_option = (string) $state_option;
		$this->hooks        = array_values( array_filter( array_map( 'strval', (array) $hooks ) ) );
		$this->min_interval = max( 1, intval( $min_interval ) );
		$this->callbacks    = is_array( $callbacks ) ? $callbacks : array();
	}

	public function should_dispatch( $now = null ) {
		$now       = null === $now ? time() : intval( $now );
		$due_hooks = $this->get_due_hooks( $now );
		if ( empty( $due_hooks ) ) {
			return false;
		}

		$state = get_option( $this->state_option, array() );
		if ( ! is_array( $state ) ) {
			$state = array();
		}

		$last_dispatch_at = intval( isset( $state['last_dispatch_at'] ) ? $state['last_dispatch_at'] : 0 );
		if ( $last_dispatch_at > ( $now - $this->min_interval ) ) {
			return false;
		}

		update_option(
			$this->state_option,
			array(
				'last_dispatch_at' => $now,
				'due_hooks'        => array_keys( $due_hooks ),
				'oldest_due_at'    => min( array_values( $due_hooks ) ),
			),
			false
		);

		$this->debug(
			'timed_automation_fallback_dispatch',
			array(
				'due_hooks' => array_keys( $due_hooks ),
			)
		);

		return true;
	}

	public function get_due_hooks( $now = null ) {
		if ( ! function_exists( '_get_cron_array' ) ) {
			return array();
		}

		$now       = null === $now ? time() : intval( $now );
		$grace     = 60;
		$hook_map  = array_fill_keys( $this->hooks, true );
		$due_hooks = array();
		$cron      = _get_cron_array();

		foreach ( is_array( $cron ) ? $cron : array() as $timestamp => $items ) {
			$timestamp = intval( $timestamp );
			if ( $timestamp < 1 || $timestamp > ( $now - $grace ) || ! is_array( $items ) ) {
				continue;
			}

			foreach ( $items as $hook => $events ) {
				if ( empty( $hook_map[ (string) $hook ] ) ) {
					continue;
				}

				if ( ! isset( $due_hooks[ $hook ] ) || $timestamp < $due_hooks[ $hook ] ) {
					$due_hooks[ $hook ] = $timestamp;
				}
			}
		}

		return $due_hooks;
	}

	private function debug( $event, $context = array() ) {
		Niwa_AI_Admin_Autonomy_Callbacks::call( $this->callbacks, 'debug_logger', array( $event, is_array( $context ) ? $context : array() ) );
	}
}
