<?php
/**
 * Jobs settings class for AgenticWP plugin.
 *
 * @package AgenticWP
 */

namespace Agentic_WP;

defined( 'ABSPATH' ) || exit;

use Agentic_WP\Error_Handler;

/**
 * Handles background jobs monitoring and management.
 */
class Settings_Jobs extends Settings_Base {

	/**
	 * Registers jobs monitoring hooks.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'wp_ajax_agenticwp_get_job_status', array( $this, 'handle_get_job_status' ) );
		add_action( 'wp_ajax_agenticwp_cleanup_jobs', array( $this, 'handle_cleanup_jobs' ) );
		add_action( 'wp_ajax_agenticwp_cancel_job', array( $this, 'handle_cancel_job' ) );
	}

	/**
	 * Renders the background jobs settings section.
	 *
	 * Displays the job monitoring interface with controls and job list.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function background_jobs_section_callback() {
		?>
		<div id="agenticwp-jobs-monitor">
			<div class="agenticwp-jobs-controls">
				<label>
					<input type="checkbox" id="agenticwp-show-completed" checked>
					<?php esc_html_e( 'Show completed jobs', 'agenticwp' ); ?>
				</label>
				<label style="margin-left: 15px;">
					<input type="checkbox" id="agenticwp-auto-refresh">
					<?php esc_html_e( 'Auto-refresh', 'agenticwp' ); ?>
				</label>
				<button type="button" id="agenticwp-refresh-jobs" class="button button-secondary" style="margin-left: 15px;">
					<span class="dashicons dashicons-update"></span>
					<?php esc_html_e( 'Refresh Now', 'agenticwp' ); ?>
				</button>
				<button type="button" id="agenticwp-cleanup-jobs" class="button button-secondary" style="margin-left: 10px;">
					<span class="dashicons dashicons-admin-tools"></span>
					<?php esc_html_e( 'Clean Up', 'agenticwp' ); ?>
				</button>
			</div>
			<div id="agenticwp-jobs-list">
				<div class="agenticwp-jobs-loading">
					<?php esc_html_e( 'Loading jobs...', 'agenticwp' ); ?>
				</div>
			</div>
		</div>
		<p class="description">
			<?php esc_html_e( 'Real-time monitoring of background job processing. Jobs are automatically updated every 5 seconds when auto-refresh is enabled.', 'agenticwp' ); ?>
		</p>
		<?php
	}

	/**
	 * AJAX handler for retrieving job status.
	 *
	 * Returns the current status of all background jobs.
	 * Also triggers piggyback loopback spawn if stale jobs are detected.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function handle_get_job_status() {
		try {
			$this->verify_ajax_request( 'agenticwp_job_status' );

			$jobs = get_option( 'agenticwp_jobs', array() );

			// Piggyback trigger: spawn loopback if stale jobs exist.
			// This ensures job processing continues even if other triggers fail.
			$stale_count = Job_Health_Monitor::get_stale_job_count( 120 );
			if ( $stale_count > 0 ) {
				Job_Health_Monitor::spawn_as_loopback( 'piggyback' );
			}

			wp_send_json_success( array( 'jobs' => $jobs ) );

		} catch ( \Throwable $e ) {
			Error_Handler::log_error(
				'ajax_handler',
				'Job status retrieval failed: ' . $e->getMessage(),
				array(
					'handler' => 'handle_get_job_status',
					'trace'   => $e->getTraceAsString(),
				)
			);

			wp_send_json_error(
				array( 'message' => __( 'Failed to retrieve job status.', 'agenticwp' ) ),
				500
			);
		}
	}

	/**
	 * AJAX handler for cleaning up completed jobs.
	 *
	 * Removes completed, failed, and cancelled jobs from the job list.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function handle_cleanup_jobs() {
		try {
			$this->verify_ajax_request( 'agenticwp_job_cleanup' );

			$jobs           = get_option( 'agenticwp_jobs', array() );
			$original_count = is_array( $jobs ) ? count( $jobs ) : 0;

			if ( ! is_array( $jobs ) || empty( $jobs ) ) {
				wp_send_json_success(
					array(
						'message' => __( 'No jobs to cleanup.', 'agenticwp' ),
						'cleaned' => 0,
						'jobs'    => array(),
					)
				);
				return;
			}

			// Filter out completed, failed, and cancelled jobs.
			$active_jobs = array_filter(
				$jobs,
				function ( $job ) {
					$status = $job['status'] ?? '';
					return ! in_array( $status, array( 'complete', 'failed', 'cancelled' ), true );
				}
			);

			$cleaned_count = $original_count - count( $active_jobs );

			update_option( 'agenticwp_jobs', $active_jobs );

			Error_Handler::debug_log(
				'Job cleanup completed',
				array(
					'cleaned_count' => $cleaned_count,
					'active_count'  => count( $active_jobs ),
				)
			);

			wp_send_json_success(
				array(
					'message' => sprintf(
						/* translators: %d is the number of jobs cleaned up. */
						_n(
							'Cleaned up %d job.',
							'Cleaned up %d jobs.',
							$cleaned_count,
							'agenticwp'
						),
						$cleaned_count
					),
					'cleaned' => $cleaned_count,
					'jobs'    => $active_jobs,
				)
			);

		} catch ( \Throwable $e ) {
			Error_Handler::log_error(
				'ajax_handler',
				'Job cleanup failed: ' . $e->getMessage(),
				array(
					'handler' => 'handle_cleanup_jobs',
					'trace'   => $e->getTraceAsString(),
				)
			);

			wp_send_json_error(
				array( 'message' => __( 'Failed to cleanup jobs.', 'agenticwp' ) ),
				500
			);
		}
	}

	/**
	 * AJAX handler for cancelling a running job.
	 *
	 * Cancels a job if it is in a cancellable state.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function handle_cancel_job() {
		try {
			$this->verify_ajax_request( 'agenticwp_job_cancel' );

			// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified by verify_ajax_request() above.
			$job_id = sanitize_text_field( wp_unslash( $_POST['job_id'] ?? '' ) );

			if ( empty( $job_id ) ) {
				Error_Handler::log_error(
					'ajax_handler',
					'Job cancellation failed: missing job_id',
					array( 'handler' => 'handle_cancel_job' )
				);

				wp_send_json_error(
					array( 'message' => __( 'Job ID is required.', 'agenticwp' ) ),
					400
				);
				return;
			}

			$jobs = get_option( 'agenticwp_jobs', array() );

			if ( ! is_array( $jobs ) || ! isset( $jobs[ $job_id ] ) ) {
				Error_Handler::log_error(
					'ajax_handler',
					'Job cancellation failed: job not found',
					array(
						'handler' => 'handle_cancel_job',
						'job_id'  => $job_id,
					)
				);

				wp_send_json_error(
					array( 'message' => __( 'Job not found.', 'agenticwp' ) ),
					404
				);
				return;
			}

			$job            = $jobs[ $job_id ];
			$current_status = $job['status'] ?? '';

			$cancellable_statuses = array( 'queued', 'starting', 'polling' );
			if ( ! in_array( $current_status, $cancellable_statuses, true ) ) {
				Error_Handler::log_error(
					'ajax_handler',
					'Job cancellation failed: invalid status',
					array(
						'handler'        => 'handle_cancel_job',
						'job_id'         => $job_id,
						'current_status' => $current_status,
					)
				);

				wp_send_json_error(
					array(
						'message' => sprintf(
							/* translators: %s is the current job status. */
							__( 'Cannot cancel job with status: %s', 'agenticwp' ),
							$current_status
						),
					),
					400
				);
				return;
			}

			$cancel_result = Background_Jobs::cancel_job( $job_id );

			if ( $cancel_result ) {
				Error_Handler::debug_log(
					'Job cancelled',
					array(
						'job_id' => $job_id,
						'status' => $current_status,
					)
				);

				wp_send_json_success(
					array(
						'message' => __( 'Job cancelled successfully.', 'agenticwp' ),
						'job_id'  => $job_id,
					)
				);
			} else {
				Error_Handler::log_error(
					'ajax_handler',
					'Job cancellation failed: cancel_job returned false',
					array(
						'handler' => 'handle_cancel_job',
						'job_id'  => $job_id,
					)
				);

				wp_send_json_error(
					array( 'message' => __( 'Failed to cancel job. Please try again.', 'agenticwp' ) ),
					500
				);
			}
		} catch ( \Throwable $e ) {
			Error_Handler::log_error(
				'ajax_handler',
				'Job cancellation failed: ' . $e->getMessage(),
				array(
					'handler' => 'handle_cancel_job',
					'job_id'  => $job_id ?? 'unknown',
					'trace'   => $e->getTraceAsString(),
				)
			);

			wp_send_json_error(
				array( 'message' => __( 'Failed to cancel job.', 'agenticwp' ) ),
				500
			);
		}
	}

	/**
	 * Get localization data for JavaScript.
	 *
	 * @return array
	 */
	public function get_localization_data(): array {
		return array(
			'jobStatusNonce'  => wp_create_nonce( 'agenticwp_job_status' ),
			'jobCleanupNonce' => wp_create_nonce( 'agenticwp_job_cleanup' ),
			'jobCancelNonce'  => wp_create_nonce( 'agenticwp_job_cancel' ),
		);
	}
}