<?php
/**
 * Remote cron trigger REST endpoint
 *
 * Allows the premium backend to trigger WordPress cron on sites with DISABLE_WP_CRON.
 * Authenticated via X-License-Key header matching the stored license key.
 *
 * @package Simple_Ai_Auto_Post
 * @since 1.0.0
 */

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
	die;
}

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

/**
 * Register REST API route for remote cron triggering.
 */
function saiap_register_cron_trigger_route() {
	register_rest_route(
		'simple-ai-auto-post/v1',
		'/trigger-cron',
		array(
			'methods'             => 'POST',
			'callback'            => 'saiap_handle_trigger_cron',
			'permission_callback' => 'saiap_verify_cron_trigger_permission',
		)
	);
}
add_action( 'rest_api_init', 'saiap_register_cron_trigger_route' );

/**
 * Verify that the request has a valid license key.
 *
 * @param WP_REST_Request $request The REST request.
 * @return bool|WP_Error True if valid, WP_Error otherwise.
 */
function saiap_verify_cron_trigger_permission( $request ) {
	$license_key_header = $request->get_header( 'X-License-Key' );

	if ( empty( $license_key_header ) ) {
		return new WP_Error(
			'missing_license_key',
			'X-License-Key header is required',
			array( 'status' => 401 )
		);
	}

	$stored_license_key = get_option( 'saiap_license_key', '' );

	if ( empty( $stored_license_key ) ) {
		if ( saiap_try_recover_license_key( $license_key_header ) ) {
			return true;
		}
		return new WP_Error(
			'no_license_configured',
			'No license key configured on this site',
			array( 'status' => 403 )
		);
	}

	if ( ! hash_equals( $stored_license_key, $license_key_header ) ) {
		return new WP_Error(
			'invalid_license_key',
			'Invalid license key',
			array( 'status' => 403 )
		);
	}

	return true;
}

/**
 * Handle the cron trigger request.
 *
 * Runs WordPress cron directly and returns information about what was processed.
 *
 * @param WP_REST_Request $request The REST request.
 * @return WP_REST_Response The response.
 */
function saiap_handle_trigger_cron( $request ) {
	// Get scheduled events before running cron.
	$crons_before = _get_cron_array();
	$due_before   = 0;
	$now          = time();

	if ( is_array( $crons_before ) ) {
		foreach ( $crons_before as $timestamp => $hooks ) {
			if ( $timestamp <= $now ) {
				$due_before += count( $hooks );
			}
		}
	}

	// Check our specific event's status BEFORE running cron.
	$saiap_event_before = saiap_get_scheduler_event_info();

	// Run cron - this executes due events directly.
	wp_cron();

	// Get scheduled events after running cron.
	$crons_after = _get_cron_array();
	$due_after   = 0;

	if ( is_array( $crons_after ) ) {
		foreach ( $crons_after as $timestamp => $hooks ) {
			if ( $timestamp <= $now ) {
				$due_after += count( $hooks );
			}
		}
	}

	// Check our specific event's status AFTER running cron.
	$saiap_event_after = saiap_get_scheduler_event_info();

	$events_processed = max( 0, $due_before - $due_after );

	// Determine if our event ran by comparing timestamps.
	$saiap_event_ran = false;
	if ( $saiap_event_before['exists'] && $saiap_event_after['exists'] ) {
		// If timestamp changed, the event ran and was rescheduled.
		$saiap_event_ran = ( $saiap_event_before['next_run_utc'] !== $saiap_event_after['next_run_utc'] );
	}

	return rest_ensure_response(
		array(
			'success'          => true,
			'events_due'       => $due_before,
			'events_processed' => $events_processed,
			'events_remaining' => $due_after,
			'timestamp'        => $now,
			'saiap_scheduler'  => array(
				'event_exists'     => $saiap_event_after['exists'],
				'event_ran'        => $saiap_event_ran,
				'next_run_utc'     => $saiap_event_after['next_run_utc'],
				'next_run_local'   => $saiap_event_after['next_run_local'],
				'seconds_until'    => $saiap_event_after['seconds_until'],
				'was_due'          => $saiap_event_before['was_due'],
				'timezone'         => $saiap_event_after['timezone'],
			),
		)
	);
}

/**
 * Get detailed info about the scheduler event.
 *
 * @return array Event information.
 */
function saiap_get_scheduler_event_info() {
	$next_scheduled = wp_next_scheduled( 'saiap_generate_scheduled_post' );
	$now            = time();
	$timezone       = wp_timezone_string();

	if ( false === $next_scheduled ) {
		return array(
			'exists'         => false,
			'next_run_utc'   => null,
			'next_run_local' => null,
			'seconds_until'  => null,
			'was_due'        => false,
			'timezone'       => $timezone,
		);
	}

	// Convert to local time for display.
	$dt_utc   = new DateTime( '@' . $next_scheduled );
	$dt_local = new DateTime( '@' . $next_scheduled );
	$dt_local->setTimezone( new DateTimeZone( $timezone ) );

	return array(
		'exists'         => true,
		'next_run_utc'   => $dt_utc->format( 'Y-m-d H:i:s' ) . ' UTC',
		'next_run_local' => $dt_local->format( 'Y-m-d H:i:s' ) . ' ' . $timezone,
		'seconds_until'  => $next_scheduled - $now,
		'was_due'        => ( $next_scheduled <= $now ),
		'timezone'       => $timezone,
	);
}
