<?php
/**
 * Google Merchant Feed Scheduler
 *
 * Handles scheduled feed regeneration via WP Cron.
 *
 * @package GGM_Commerce
 * @since 1.0.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class GGM_Commerce_Google_Merchant_Scheduler
 *
 * Manages WP Cron schedules for feed regeneration.
 */
class GGM_Commerce_Google_Merchant_Scheduler {

	/**
	 * Cron hook names.
	 */
	const CRON_HOOK_HOURLY     = 'ggm_commerce_google_feed_hourly';
	const CRON_HOOK_TWICEDAILY = 'ggm_commerce_google_feed_twicedaily';
	const CRON_HOOK_DAILY      = 'ggm_commerce_google_feed_daily';
	const CRON_HOOK_WEEKLY     = 'ggm_commerce_google_feed_weekly';

	/**
	 * Singleton instance.
	 *
	 * @var GGM_Commerce_Google_Merchant_Scheduler|null
	 */
	private static $instance = null;

	/**
	 * Get singleton instance.
	 *
	 * @return GGM_Commerce_Google_Merchant_Scheduler
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Private constructor for singleton.
	 */
	private function __construct() {
		$this->register_hooks();
	}

	/**
	 * Register cron hooks.
	 */
	private function register_hooks() {
		// Register cron event handlers.
		add_action( self::CRON_HOOK_HOURLY, array( $this, 'run_hourly_feeds' ) );
		add_action( self::CRON_HOOK_TWICEDAILY, array( $this, 'run_twicedaily_feeds' ) );
		add_action( self::CRON_HOOK_DAILY, array( $this, 'run_daily_feeds' ) );
		add_action( self::CRON_HOOK_WEEKLY, array( $this, 'run_weekly_feeds' ) );

		// Invalidate feeds on product changes.
		add_action( 'ggmc_product_saved', array( $this, 'on_product_change' ) );
		add_action( 'ggmc_product_deleted', array( $this, 'on_product_change' ) );
		add_action( 'ggmc_product_updated', array( $this, 'on_product_change' ) );
	}

	/**
	 * Schedule all cron events.
	 *
	 * Should be called on plugin activation or when settings change.
	 */
	public function schedule_all() {
		// Only schedule if feature is activated.
		if ( ! GGM_Commerce_Google_Merchant_Feed::is_activated() ) {
			return;
		}

		$this->schedule_event( self::CRON_HOOK_HOURLY, 'hourly' );
		$this->schedule_event( self::CRON_HOOK_TWICEDAILY, 'twicedaily' );
		$this->schedule_event( self::CRON_HOOK_DAILY, 'daily' );
		$this->schedule_event( self::CRON_HOOK_WEEKLY, 'weekly' );
	}

	/**
	 * Schedule a single event if not already scheduled.
	 *
	 * @param string $hook     Cron hook name.
	 * @param string $schedule WordPress schedule name.
	 */
	private function schedule_event( $hook, $schedule ) {
		if ( ! wp_next_scheduled( $hook ) ) {
			wp_schedule_event( time(), $schedule, $hook );
		}
	}

	/**
	 * Unschedule all cron events.
	 *
	 * Should be called on plugin deactivation.
	 */
	public function unschedule_all() {
		$hooks = array(
			self::CRON_HOOK_HOURLY,
			self::CRON_HOOK_TWICEDAILY,
			self::CRON_HOOK_DAILY,
			self::CRON_HOOK_WEEKLY,
		);

		foreach ( $hooks as $hook ) {
			$timestamp = wp_next_scheduled( $hook );
			if ( $timestamp ) {
				wp_unschedule_event( $timestamp, $hook );
			}
		}
	}

	/**
	 * Run hourly feeds.
	 */
	public function run_hourly_feeds() {
		$this->regenerate_feeds_by_schedule( 'hourly' );
	}

	/**
	 * Run twice daily feeds.
	 */
	public function run_twicedaily_feeds() {
		$this->regenerate_feeds_by_schedule( 'twicedaily' );
	}

	/**
	 * Run daily feeds.
	 */
	public function run_daily_feeds() {
		$this->regenerate_feeds_by_schedule( 'daily' );
	}

	/**
	 * Run weekly feeds.
	 */
	public function run_weekly_feeds() {
		$this->regenerate_feeds_by_schedule( 'weekly' );
	}

	/**
	 * Regenerate all feeds with a given schedule.
	 *
	 * @param string $schedule Schedule interval.
	 */
	private function regenerate_feeds_by_schedule( $schedule ) {
		// Check if feature is still activated.
		if ( ! GGM_Commerce_Google_Merchant_Feed::is_activated() ) {
			return;
		}

		$feed_manager = GGM_Commerce_Google_Merchant_Feed_Manager::instance();
		$feeds        = $feed_manager->get_feeds_by_schedule( $schedule );

		if ( empty( $feeds ) ) {
			return;
		}

		$generator = GGM_Commerce_Google_Merchant_Feed::instance();
		$validator = GGM_Commerce_Google_Merchant_Validator::instance();

		foreach ( $feeds as $feed_id => $feed ) {
			$validator->reset();
			$generator->set_validator( $validator );
			$generator->generate_feed( $feed_id );

			// Log for debugging.
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
				error_log( sprintf( 'GGM Commerce: Generated Google Merchant feed "%s"', $feed_id ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			}
		}
	}

	/**
	 * Handle product changes.
	 *
	 * Optionally mark feeds as needing regeneration or regenerate immediately.
	 *
	 * @param int $product_id Product ID.
	 */
	public function on_product_change( $product_id ) {
		// For now, we'll just let the scheduled regeneration handle it.
		// Could add logic here to mark feeds as stale or trigger immediate regeneration.

		/**
		 * Action fired when a product changes that might affect feeds.
		 *
		 * @param int $product_id The changed product ID.
		 */
		do_action( 'ggm_commerce_google_feed_product_changed', $product_id );
	}

	/**
	 * Regenerate all active feeds immediately.
	 *
	 * @return array Results for each feed.
	 */
	public function regenerate_all_feeds() {
		if ( ! GGM_Commerce_Google_Merchant_Feed::is_activated() ) {
			return array( 'error' => 'Feature not activated' );
		}

		$feed_manager = GGM_Commerce_Google_Merchant_Feed_Manager::instance();
		$feeds        = $feed_manager->get_active_feeds();
		$results      = array();

		$generator = GGM_Commerce_Google_Merchant_Feed::instance();
		$validator = GGM_Commerce_Google_Merchant_Validator::instance();

		foreach ( $feeds as $feed_id => $feed ) {
			$validator->reset();
			$generator->set_validator( $validator );
			$result = $generator->generate_feed( $feed_id );

			$results[ $feed_id ] = array(
				'success'       => ! is_wp_error( $result ),
				'product_count' => is_wp_error( $result ) ? 0 : $result['product_count'],
				'error_count'   => is_wp_error( $result ) ? 0 : $result['error_count'],
				'error'         => is_wp_error( $result ) ? $result->get_error_message() : null,
			);
		}

		return $results;
	}

	/**
	 * Get next scheduled time for a feed's schedule.
	 *
	 * @param string $schedule Schedule interval.
	 * @return int|false Timestamp or false if not scheduled.
	 */
	public function get_next_scheduled( $schedule ) {
		$hook = $this->get_hook_for_schedule( $schedule );
		return wp_next_scheduled( $hook );
	}

	/**
	 * Get the hook name for a schedule.
	 *
	 * @param string $schedule Schedule interval.
	 * @return string
	 */
	private function get_hook_for_schedule( $schedule ) {
		switch ( $schedule ) {
			case 'hourly':
				return self::CRON_HOOK_HOURLY;
			case 'twicedaily':
				return self::CRON_HOOK_TWICEDAILY;
			case 'daily':
				return self::CRON_HOOK_DAILY;
			case 'weekly':
				return self::CRON_HOOK_WEEKLY;
			default:
				return self::CRON_HOOK_DAILY;
		}
	}

	/**
	 * Get schedule status for all cron hooks.
	 *
	 * @return array
	 */
	public function get_schedule_status() {
		return array(
			'hourly'     => array(
				'next_run' => wp_next_scheduled( self::CRON_HOOK_HOURLY ),
				'active'   => (bool) wp_next_scheduled( self::CRON_HOOK_HOURLY ),
			),
			'twicedaily' => array(
				'next_run' => wp_next_scheduled( self::CRON_HOOK_TWICEDAILY ),
				'active'   => (bool) wp_next_scheduled( self::CRON_HOOK_TWICEDAILY ),
			),
			'daily'      => array(
				'next_run' => wp_next_scheduled( self::CRON_HOOK_DAILY ),
				'active'   => (bool) wp_next_scheduled( self::CRON_HOOK_DAILY ),
			),
			'weekly'     => array(
				'next_run' => wp_next_scheduled( self::CRON_HOOK_WEEKLY ),
				'active'   => (bool) wp_next_scheduled( self::CRON_HOOK_WEEKLY ),
			),
		);
	}
}
