<?php
/**
 * Cron class.
 *
 * @package Social_Post_Flow
 * @author Social Post Flow
 */

/**
 * Functions to schedule, reschedule and unschedule events with WordPress' Cron for
 * - Log Cleanup (old log entries that are no longer needed)
 * - Media Cleanup (images auto generated by the Plugin that are no longer needed)
 * - Repost Post(s)
 *
 * @package  Social_Post_Flow
 * @author   Social Post Flow
 */
class Social_Post_Flow_Cron {

	/**
	 * Schedules the log cleanup event in the WordPress CRON on a daily basis
	 *
	 * @since   1.0.0
	 */
	public function schedule_log_cleanup_event() {

		// Bail if the preserve logs settings is indefinite.
		if ( ! social_post_flow()->get_class( 'settings' )->get_setting( 'log', '[preserve_days]' ) ) {
			return;
		}

		// Bail if the scheduled event already exists.
		$scheduled_event = $this->get_log_cleanup_event();
		if ( $scheduled_event !== false ) {
			return;
		}

		// Schedule event.
		$scheduled_date_time = gmdate( 'Y-m-d', strtotime( '+1 day' ) ) . ' 00:00:00';
		wp_schedule_event( strtotime( $scheduled_date_time ), 'daily', 'social_post_flow_log_cleanup_cron' );

	}

	/**
	 * Unschedules the log cleanup event in the WordPress CRON.
	 *
	 * @since   1.0.0
	 */
	public function unschedule_log_cleanup_event() {

		wp_clear_scheduled_hook( 'social_post_flow_log_cleanup_cron' );

	}

	/**
	 * Reschedules the log cleanup event in the WordPress CRON, by unscheduling
	 * and scheduling it.
	 *
	 * @since   1.0.0
	 */
	public function reschedule_log_cleanup_event() {

		$this->unschedule_log_cleanup_event();
		$this->schedule_log_cleanup_event();

	}

	/**
	 * Returns the scheduled log cleanup event, if it exists
	 *
	 * @since   1.0.0
	 */
	public function get_log_cleanup_event() {

		return wp_get_schedule( 'social_post_flow_log_cleanup_cron' );

	}

	/**
	 * Returns the scheduled log cleanup event's next date and time to run, if it exists
	 *
	 * @since   1.0.0
	 *
	 * @param   mixed $format     Format Timestamp (false | php date() compat. string).
	 */
	public function get_log_cleanup_event_next_scheduled( $format = false ) {

		// Get timestamp for when the event will next run.
		$scheduled = wp_next_scheduled( 'social_post_flow_log_cleanup_cron' );

		// If no timestamp or we're not formatting the result, return it now.
		if ( ! $scheduled || ! $format ) {
			return $scheduled;
		}

		// Return formatted date/time.
		return date( $format, $scheduled ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
	}

	/**
	 * Schedules the media cleanup event in the WordPress CRON on a daily basis
	 *
	 * @since   1.0.0
	 */
	public function schedule_media_cleanup_event() {

		// Bail if the scheduled event already exists.
		$scheduled_event = $this->get_media_cleanup_event();
		if ( $scheduled_event !== false ) {
			return;
		}

		// Schedule event.
		$scheduled_date_time = gmdate( 'Y-m-d', strtotime( '+1 day' ) ) . ' 01:00:00';
		wp_schedule_event( strtotime( $scheduled_date_time ), 'daily', 'social_post_flow_media_cleanup_cron' );

	}

	/**
	 * Unschedules the media cleanup event in the WordPress CRON.
	 *
	 * @since   1.0.0
	 */
	public function unschedule_media_cleanup_event() {

		wp_clear_scheduled_hook( 'social_post_flow_media_cleanup_cron' );

	}

	/**
	 * Reschedules the media cleanup event in the WordPress CRON, by unscheduling
	 * and scheduling it.
	 *
	 * @since   1.0.0
	 */
	public function reschedule_media_cleanup_event() {

		$this->unschedule_media_cleanup_event();
		$this->schedule_media_cleanup_event();

	}

	/**
	 * Returns the scheduled media cleanup event, if it exists
	 *
	 * @since   1.0.0
	 */
	public function get_media_cleanup_event() {

		return wp_get_schedule( 'social_post_flow_media_cleanup_cron' );

	}

	/**
	 * Returns the scheduled media cleanup event's next date and time to run, if it exists
	 *
	 * @since   1.0.0
	 *
	 * @param   mixed $format     Format Timestamp (false | php date() compat. string).
	 */
	public function get_media_cleanup_event_next_scheduled( $format = false ) {

		// Get timestamp for when the event will next run.
		$scheduled = wp_next_scheduled( 'social_post_flow_media_cleanup_cron' );

		// If no timestamp or we're not formatting the result, return it now.
		if ( ! $scheduled || ! $format ) {
			return $scheduled;
		}

		// Return formatted date/time.
		return date( $format, $scheduled ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
	}

	/**
	 * Schedules the repost event in the WordPress CRON on an hourly basis, based on the Plugin
	 * Setting's scheduled time.
	 *
	 * @since   1.0.0
	 */
	public function schedule_repost_event() {

		// Bail if the repost cron is disabled.
		if ( social_post_flow()->get_class( 'settings' )->get_option( 'repost_disable_cron', 0 ) ) {
			return;
		}

		// Bail if the scheduled event already exists.
		$scheduled_event = $this->get_repost_event();
		if ( $scheduled_event !== false ) {
			return;
		}

		// Schedule event.
		$scheduled_date_time = gmdate( 'Y-m-d H', strtotime( '+1 hour' ) ) . ':00:00';
		wp_schedule_event( strtotime( $scheduled_date_time ), 'hourly', 'social_post_flow_repost_cron' );

	}

	/**
	 * Unschedules the repost event in the WordPress CRON.
	 *
	 * @since   1.0.0
	 */
	public function unschedule_repost_event() {

		wp_clear_scheduled_hook( 'social_post_flow_repost_cron' );

	}

	/**
	 * Reschedules the repost event in the WordPress CRON, by unscheduling
	 * and scheduling it.
	 *
	 * @since   1.0.0
	 */
	public function reschedule_repost_event() {

		$this->unschedule_repost_event();
		$this->schedule_repost_event();

	}

	/**
	 * Returns the scheduled repost event, if it exists
	 *
	 * @since   1.0.0
	 */
	public function get_repost_event() {

		return wp_get_schedule( 'social_post_flow_repost_cron' );

	}

	/**
	 * Returns the scheduled repost event's next date and time to run, if it exists
	 *
	 * @since   1.0.0
	 *
	 * @param   mixed $format     Format Timestamp (false | php date() compat. string).
	 */
	public function get_repost_event_next_scheduled( $format = false ) {

		// Get timestamp for when the event will next run.
		$scheduled = wp_next_scheduled( 'social_post_flow_repost_cron' );

		// If no timestamp or we're not formatting the result, return it now.
		if ( ! $scheduled || ! $format ) {
			return $scheduled;
		}

		// Return formatted date/time.
		return date( $format, $scheduled ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
	}

	/**
	 * Schedules the user access event in the WordPress CRON on a daily basis
	 *
	 * @since   1.1.7
	 */
	public function schedule_user_access_event() {

		// Bail if the scheduled event already exists.
		$scheduled_event = $this->get_user_access_event();
		if ( $scheduled_event !== false ) {
			return;
		}

		// Schedule event.
		$scheduled_date_time = gmdate( 'Y-m-d', strtotime( '+1 day' ) ) . ' 01:00:00';
		wp_schedule_event( strtotime( $scheduled_date_time ), 'daily', 'social_post_flow_user_access_cron' );

	}

	/**
	 * Unschedules the user access event in the WordPress CRON.
	 *
	 * @since   1.1.7
	 */
	public function unschedule_user_access_event() {

		wp_clear_scheduled_hook( 'social_post_flow_user_access_cron' );

	}

	/**
	 * Reschedules the user access event in the WordPress CRON, by unscheduling
	 * and scheduling it.
	 *
	 * @since   1.1.7
	 */
	public function reschedule_user_access_event() {

		$this->unschedule_user_access_event();
		$this->schedule_user_access_event();

	}

	/**
	 * Returns the scheduled user access event, if it exists
	 *
	 * @since   1.1.7
	 */
	public function get_user_access_event() {

		return wp_get_schedule( 'social_post_flow_user_access_cron' );

	}

	/**
	 * Returns the user access event's next date and time to run, if it exists
	 *
	 * @since   1.1.7
	 *
	 * @param   mixed $format     Format Timestamp (false | php date() compat. string).
	 */
	public function get_user_access_event_next_scheduled( $format = false ) {

		// Get timestamp for when the event will next run.
		$scheduled = wp_next_scheduled( 'social_post_flow_user_access_cron' );

		// If no timestamp or we're not formatting the result, return it now.
		if ( ! $scheduled || ! $format ) {
			return $scheduled;
		}

		// Return formatted date/time.
		return date( $format, $scheduled ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date

	}

	/**
	 * Runs the publish CRON event for the given Post ID.
	 *
	 * Calls Social_Post_Flow_Publish::publish() to compile statuses and send them.
	 *
	 * @since   1.0.0
	 *
	 * @param   int    $post_id    Post ID.
	 * @param   string $action     Action.
	 */
	public function publish( $post_id, $action ) {

		// Get Test Mode Flag.
		$test_mode = social_post_flow()->get_class( 'settings' )->get_option( 'test_mode', false );

		// Send request to the API.
		social_post_flow()->get_class( 'publish' )->publish( $post_id, $action, $test_mode );

		// Clear the log of any 'Pending' statuses (i.e. log entries telling the user that the status
		// was added to the WordPress Cron).
		social_post_flow()->get_class( 'log' )->delete_pending_by_post_id( $post_id );

	}

	/**
	 * Runs the repost CRON event
	 *
	 * @since   1.0.0
	 *
	 * @param   bool $test_mode      Test Mode (don't send to API).
	 */
	public function repost( $test_mode = false ) {

		social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Started' );
		social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Test Mode: ' . $test_mode );

		// Bail if repost cron is disabled.
		// We shouldn't ever call this function if this is the case, but it's a useful sanity check.
		if ( social_post_flow()->get_class( 'settings' )->get_setting( 'repost_disable_cron', 0 ) ) {
			social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Stopped, as Settings > Repost Settings > Disable Repost Cron is selected' );
			return;
		}

		// Bail if no Repost Schedule exists.
		$repost_schedule = social_post_flow()->get_class( 'settings' )->get_option( 'repost_time', false );
		if ( ! $repost_schedule ) {
			social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Stopped, as Settings > Repost Settings > Repost Times are empty' );
			return;
		}

		// Get current day and hour based on the WordPress timezone.
		$current_timestamp = current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp

		// mon,tue etc.
		$current_day = strtolower( date( 'D', $current_timestamp ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date

		// 00,01 etc.
		$current_hour = date( 'H', $current_timestamp ) . ':00'; // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date

		// Bail if no Repost Schedule exists for today.
		if ( ! isset( $repost_schedule[ $current_day ] ) ) {
			social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Stopped, as Settings > Repost Settings has no schedule for Day ' . $current_day );
			return;
		}
		if ( ! $repost_schedule[ $current_day ] ) {
			social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Stopped, as Settings > Repost Settings has no schedule for Day ' . $current_day );
			return;
		}

		// Bail if this hour isn't in the Repost Schedule.
		if ( ! in_array( $current_hour, $repost_schedule[ $current_day ], true ) ) {
			social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Stopped, as Settings > Repost Settings is not set to run on Day ' . $current_day . ', Hour ' . $current_hour );
			return;
		}

		// If here, run the Repost action.
		social_post_flow()->get_class( 'repost' )->run( false, $test_mode );

		social_post_flow()->get_class( 'log' )->add_to_debug_log( 'Social Post Flow: repost(): Finished' );

	}

	/**
	 * Runs the log cleanup CRON event
	 *
	 * @since   1.0.0
	 */
	public function log_cleanup() {

		// Bail if the preserve logs settings is indefinite.
		// We shouldn't ever call this function if this is the case, but it's a useful sanity check.
		$preserve_days = social_post_flow()->get_class( 'settings' )->get_setting( 'log', '[preserve_days]' );
		if ( ! $preserve_days ) {
			return;
		}

		// Define the date cutoff.
		$date_time = date( 'Y-m-d H:i:s', strtotime( '-' . $preserve_days . ' days' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
		// Delete log entries older than the date.
		social_post_flow()->get_class( 'log' )->delete_by_request_sent_cutoff( $date_time );

	}

}
