<?php
/**
 * Cron scheduling and background processing.
 * 
 * @package WPStaticHTMLPages
 */

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

class WPSH_Cron {

	/**
	 * Initialize cron hooks.
	 */
	public function init() {
		add_action( 'wpsh_twicedaily_cache_refresh', array( $this, 'cache_refresh' ) );
		add_action( 'wpsh_cron_regen_batch', array( $this, 'process_batch' ) );
		
		// Add custom cron schedule if it doesn't exist, though twicedaily is standard WP.
		add_filter( 'cron_schedules', array( $this, 'add_cron_schedules' ) );
	}

	/**
	 * Add custom cron schedules if needed.
	 */
	public function add_cron_schedules( $schedules ) {
		if ( ! isset( $schedules['twicedaily'] ) ) {
			$schedules['twicedaily'] = array(
				'interval' => 43200, // 12 hours
				'display'  => __( 'Twice Daily', 'moon-static-html-pages' )
			);
		}
		return $schedules;
	}

	/**
	 * Whether automated cache regeneration is allowed.
	 *
	 * @return bool
	 */
	public function is_auto_generation_enabled() {
		return (bool) apply_filters( 'wpsh_auto_generation_enabled', false );
	}

	/**
	 * Schedule the twicedaily event. Usually called on plugin activation.
	 */
	public function schedule_events() {
		if ( ! $this->is_auto_generation_enabled() ) {
			WPSH_Logger::info( 'Automated cache refresh is disabled by filter; skipping schedule.' );
			return;
		}

		if ( ! wp_next_scheduled( 'wpsh_twicedaily_cache_refresh' ) ) {
			// Schedule it to run twice a day starting now
			wp_schedule_event( time(), 'twicedaily', 'wpsh_twicedaily_cache_refresh' );
			WPSH_Logger::info( 'Scheduled twice-daily automated cache refresh.' );
		}
	}

	/**
	 * Clear scheduled events. Usually called on plugin deactivation.
	 */
	public function clear_events() {
		wp_clear_scheduled_hook( 'wpsh_twicedaily_cache_refresh' );
		wp_clear_scheduled_hook( 'wpsh_cron_regen_batch' );
		delete_option( 'wpsh_cron_regen_state' );
		WPSH_Logger::info( 'Cleared scheduled cron events.' );
	}

	/**
	 * Main entry point for the automated twicedaily cron.
	 * Clears the cache directory and kicks off the background generation.
	 */
	public function cache_refresh() {
		WPSH_Logger::info( 'Automated Cron: Starting twice-daily cache refresh process.' );

		global $wp_filesystem;
		if ( empty( $wp_filesystem ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
			WP_Filesystem();
		}
		
		$dir = WPSH_Helper::get_dir();
		if ( $wp_filesystem->exists( $dir ) ) {
			$deleted = $wp_filesystem->delete( $dir, true );
			wp_mkdir_p( $dir );
			WPSH_Logger::info( 'Automated Cron: Cache directory cleared.' );
		}

		// Initialize background regeneration state
		$state = array(
			'phase'  => 'posts',
			'offset' => 0,
			'started'=> current_time( 'timestamp' )
		);
		update_option( 'wpsh_cron_regen_state', $state );

		// Schedule the first batch
		if ( ! wp_next_scheduled( 'wpsh_cron_regen_batch' ) ) {
			wp_schedule_single_event( time() + 5, 'wpsh_cron_regen_batch' );
			WPSH_Logger::info( 'Automated Cron: Scheduled first regeneration batch.' );
		}
	}

	/**
	 * Processes a chunk of the cache generation to avoid timeouts.
	 */
	public function process_batch() {
		$state = get_option( 'wpsh_cron_regen_state' );
		
		if ( empty( $state ) || ! is_array( $state ) ) {
			// No active generation process
			return;
		}

		// If generation was interrupted manually via admin
		if ( get_option( 'wpsh_interrupt_flag' ) === '1' ) {
			WPSH_Logger::warning( 'Automated Cron: Generation was interrupted by admin flag. Stopping cron regeneration.' );
			delete_option( 'wpsh_cron_regen_state' );
			return;
		}

		$phase  = isset( $state['phase'] ) ? $state['phase'] : 'posts';
		$offset = isset( $state['offset'] ) ? (int) $state['offset'] : 0;
		$limit  = max( 1, (int) apply_filters( 'wpsh_generation_batch_limit', 5 ) );
		$core   = new WPSH_Core();

		$is_phase_complete = false;
		$processed_count   = 0;

		if ( $phase === 'posts' ) {
			// On the very first run, handle the base archive URLs and custom mapped CPT listing pages
			if ( $offset === 0 ) {
				$special_urls = array_merge( 
					$core->get_archive_base_urls(), 
					$core->get_all_cpt_listing_generation_urls() 
				);
				
				foreach ( $special_urls as $url ) {
					$result = $core->generate_html_by_url( $url );
					if ( true !== $result && $core->maybe_queue_retryable_generation( $url, $result ) ) {
						// Queued for background retry
					}
				}
			}

			$excluded_types = (array) get_option( 'wpsh_excluded_post_types', array() );
			$public_types   = get_post_types( array( 'public' => true ) );
			$eligible_types = array_diff( $public_types, $excluded_types );

			$args = array(
				'post_type'      => $eligible_types ?: 'none',
				'post_status'    => 'publish',
				'posts_per_page' => $limit,
				'offset'         => $offset,
				'fields'         => 'ids',
				'orderby'        => 'ID',
				'order'          => 'ASC'
			);
			
			$query = new WP_Query( $args );
			$posts = $query->posts;

			foreach ( $posts as $post_id ) {
				if ( ! WPSH_Helper::is_excluded( $post_id ) ) {
					$url = get_permalink( $post_id );
					$result = $core->generate_html_by_url( $url );
					if ( true !== $result ) {
						$core->maybe_queue_retryable_generation( $url, $result );
					}
				}
				$processed_count++;
			}
			
			$is_phase_complete = ( count( $posts ) < $limit ) && ( $processed_count === count( $posts ) );
			
			if ( $is_phase_complete ) {
				$state['phase']  = 'archive_pagination';
				$state['offset'] = 0;
			} else {
				$state['offset'] = $offset + $processed_count;
			}
			
		} elseif ( $phase === 'archive_pagination' ) {
			$pagination_items = $core->get_archive_pagination_items( $offset, $limit );

			foreach ( $pagination_items as $item ) {
				$result = $core->generate_html_by_url( $item['url'] );
				if ( true !== $result ) {
					$core->maybe_queue_retryable_generation( $item['url'], $result );
				}
				$processed_count++;
			}

			$is_phase_complete = ( count( $pagination_items ) < $limit ) && ( $processed_count === count( $pagination_items ) );
			
			if ( $is_phase_complete ) {
				$core->cleanup_all_stale_archive_pagination();
				$state['phase']  = 'terms';
				$state['offset'] = 0;
			} else {
				$state['offset'] = $offset + $processed_count;
			}

		} elseif ( $phase === 'terms' ) {
			$excluded_tax = (array) get_option( 'wpsh_excluded_taxonomies', array() );
			$taxonomies   = get_taxonomies( array( 'public' => true ), 'names' );
			$eligible_tax = array_diff( $taxonomies, $excluded_tax );

			if ( ! empty( $eligible_tax ) ) {
				$all_terms = get_terms( array(
					'taxonomy'   => $eligible_tax,
					'hide_empty' => true,
					'number'     => $limit,
					'offset'     => $offset,
					'fields'     => 'ids'
				) );
				
				if ( ! is_wp_error( $all_terms ) && ! empty( $all_terms ) ) {
					foreach ( $all_terms as $term_id ) {
						$term = get_term( $term_id );
						if ( $term && ! is_wp_error( $term ) ) {
							$url = get_term_link( $term );
							if ( ! is_wp_error( $url ) ) {
								$result = $core->generate_html_by_url( $url );
								if ( true !== $result ) {
									$core->maybe_queue_retryable_generation( $url, $result );
								}
							}
						}
						$processed_count++;
					}
					$is_phase_complete = ( count( $all_terms ) < $limit ) && ( $processed_count === count( $all_terms ) );
				} else {
					$is_phase_complete = true;
				}
			} else {
				$is_phase_complete = true;
			}

			if ( $is_phase_complete ) {
				$state['phase'] = 'done';
			} else {
				$state['offset'] = $offset + $processed_count;
			}
		}

		if ( isset( $state['phase'] ) && $state['phase'] === 'done' ) {
			// We are fully finished
			delete_option( 'wpsh_cron_regen_state' );
			$time = current_time( 'timestamp' );
			update_option( 'wpsh_last_generated', $time );
			WPSH_Logger::info( 'Automated Cron: Cache regeneration completed successfully.' );
		} else {
			// Save the updated state and schedule next batch
			update_option( 'wpsh_cron_regen_state', $state );
			if ( ! wp_next_scheduled( 'wpsh_cron_regen_batch' ) ) {
				wp_schedule_single_event( time() + 5, 'wpsh_cron_regen_batch' );
			}
		}
	}
}
