<?php
/**
 * WP Cron Event List Tool.
 *
 * Allows the agent to list all scheduled WordPress cron events with filtering
 * and pagination support.
 *
 * @package   Agenistrator
 * @since     1.0.0
 * @author    Alex Ruban <alex@maximum.guru>
 * @author    Maximum Software Inc <contact@maximum.software>
 * @license   GPL-3.0-only
 * @link      https://agenistrator.com/
 *
 * SPDX-FileCopyrightText: 2025-2026 Alex Ruban <alex@maximum.guru>
 * SPDX-FileCopyrightText: 2025-2026 Maximum Software Inc <contact@maximum.software>
 * SPDX-License-Identifier: GPL-3.0-only
 */

namespace Agenistrator;

// Direct access prevention
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * WP_Cron_Event_List_Tool class.
 */
class WP_Cron_Event_List_Tool extends Tool {

	/**
	 * Get the tool ID.
	 *
	 * @return string The tool ID.
	 * @since     1.0.0
	 */
	public function get_id() {
		return 'list_cron_events';
	}

	/**
	 * Get the tool name.
	 *
	 * @return string The tool name.
	 * @since     1.0.0
	 */
	public function get_name() {
		return __( 'List Cron Events', 'agenistrator' );
	}

	/**
	 * Get the description of the tool.
	 *
	 * @return string The description of the tool.
	 * @since     1.0.0
	 */
	public function get_description() {
		return 'Lists all scheduled WordPress cron events with their next run times, recurrence, and hook names.';
	}

	/**
	 * Get the parameters for this tool.
	 *
	 * @return array Parameters schema in JSON Schema format.
	 * @since     1.0.0
	 */
	public function get_parameters() {
		return array(
			'type'       => 'object',
			'properties' => array(
				'hook'   => array(
					'type'        => 'string',
					'description' => 'Filter events by hook name (optional).',
				),
				'status' => array(
					'type'        => 'string',
					'description' => 'Filter by status: "due" for events ready to run, "pending" for future events (optional).',
					'enum'        => array( 'due', 'pending' ),
				),
				'limit'  => array(
					'type'        => 'integer',
					'description' => 'Maximum number of events to return. Default: 100.',
				),
				'offset' => array(
					'type'        => 'integer',
					'description' => 'Number of events to skip before returning results. Default: 0.',
				),
			),
			'required'   => array(),
		);
	}

	/**
	 * Check if the current user has permission to execute this tool.
	 *
	 * @return bool Whether the user has permission.
	 * @since     1.0.0
	 */
	public function current_user_can_execute() {
		return current_user_can( 'manage_options' );
	}

	/**
	 * Check if this tool is read-only.
	 *
	 * @return bool True - this tool only retrieves data.
	 * @since     1.0.0
	 */
	public function is_read_only() {
		return true;
	}

	/**
	 * Execute the tool with the given arguments.
	 *
	 * @param array $args The arguments for the tool.
	 * @return array The result of executing the tool.
	 * @since     1.0.0
	 */
	protected function execute( $args ) {
		$crons  = _get_cron_array();
		$limit  = max( 1, isset( $args['limit'] ) ? (int) $args['limit'] : 100 );
		$offset = max( 0, isset( $args['offset'] ) ? (int) $args['offset'] : 0 );

		if ( empty( $crons ) ) {
			return $this->success_response(
				'No cron events found',
				array(
					'events'   => array(),
					'count'    => 0,
					'total'    => 0,
					'limit'    => $limit,
					'offset'   => $offset,
					'has_more' => false,
				)
			);
		}

		$events        = array();
		$now           = time();
		$schedules     = wp_get_schedules();
		$hook_filter   = $args['hook'] ?? null;
		$status_filter = $args['status'] ?? null;

		foreach ( $crons as $timestamp => $cron_hooks ) {
			foreach ( $cron_hooks as $hook => $hook_events ) {
				// Filter by hook if specified.
				if ( $hook_filter && $hook !== $hook_filter ) {
					continue;
				}

				foreach ( $hook_events as $event_data ) {
					$is_due = $timestamp <= $now;

					// Filter by status if specified.
					if ( $status_filter ) {
						if ( 'due' === $status_filter && ! $is_due ) {
							continue;
						}
						if ( 'pending' === $status_filter && $is_due ) {
							continue;
						}
					}

					$schedule_name    = $event_data['schedule'] ?? false;
					$schedule_display = $schedule_name;
					if ( $schedule_name && isset( $schedules[ $schedule_name ] ) ) {
						$schedule_display = $schedules[ $schedule_name ]['display'];
					}

					$events[] = array(
						'hook'             => $hook,
						'next_run'         => $timestamp,
						'next_run_date'    => gmdate( 'Y-m-d H:i:s e', $timestamp ),
						'schedule'         => $schedule_name ? $schedule_name : 'one-time',
						'schedule_display' => $schedule_display ? $schedule_display : 'One-time',
						'interval'         => $event_data['interval'] ?? null,
						'args'             => $event_data['args'] ?? array(),
						'is_due'           => $is_due,
					);
				}
			}
		}

		// Sort by next run time.
		usort(
			$events,
			function ( $a, $b ) {
				return $a['next_run'] - $b['next_run'];
			}
		);

		// Apply pagination
		$total     = count( $events );
		$paginated = array_slice( $events, $offset, $limit );
		$has_more  = $total > ( $offset + $limit );

		return $this->success_response(
			'Cron events retrieved successfully',
			array(
				'events'   => $paginated,
				'count'    => count( $paginated ),
				'total'    => $total,
				'limit'    => $limit,
				'offset'   => $offset,
				'has_more' => $has_more,
			)
		);
	}
}
