<?php
/**
 * Admin tool used to automatically reschedule recurring orders missing a pending scheduled payment action
 *
 * @package LifterLMS/Admin/Tools/Classes
 *
 * @since 4.6.0
 * @version 4.7.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * LLMS_Admin_Tool_Recurring_Payment_Rescheduler class
 *
 * @since 4.6.0
 */
class LLMS_Admin_Tool_Recurring_Payment_Rescheduler extends LLMS_Abstract_Admin_Tool {

	/**
	 * Tool ID.
	 *
	 * @var string
	 */
	protected $id = 'recurring-payment-rescheduler';

	/**
	 * Retrieve a description of the tool
	 *
	 * This is displayed on the right side of the tool's list before the button.
	 *
	 * @since 4.6.0
	 * @since 4.7.0 Modified language and use count from `FOUND_ROWS()`.
	 *
	 * @return string
	 */
	protected function get_description() {

		$orders = $this->get_orders();
		$count  = wp_cache_get( sprintf( '%s-total-results', $this->id ), 'llms_tool_data' );

		$desc  = __( 'Check active recurring orders to ensure their recurring payment action is properly scheduled for the next payment. If a recurring payment is due and not scheduled it will be rescheduled.', 'lifterlms' );
		$desc .= ' ';
		// Translators: %d = the number of pending batches.
		$desc .= sprintf(
			_n(
				'There is %d order that will be checked.',
				'There are %d orders that will be checked in batches of 50.',
				$count,
				'lifterlms'
			),
			$count
		);

		return $desc;

	}

	/**
	 * Retrieve the tool's label
	 *
	 * The label is the tool's title. It's displayed in the left column on the tool's list.
	 *
	 * @since 4.6.0
	 *
	 * @return string
	 */
	protected function get_label() {
		return __( 'Reschedule Recurring Payments', 'lifterlms' );
	}

	/**
	 * Retrieve the tool's button text
	 *
	 * @since 4.6.0
	 *
	 * @return string
	 */
	protected function get_text() {
		return __( 'Reschedule Payments', 'lifterlms' );
	}

	/**
	 * Retrieve a list of orders
	 *
	 * @since 4.6.0
	 *
	 * @return int[]
	 */
	protected function get_orders() {

		$orders = wp_cache_get( $this->id, 'llms_tool_data' );
		if ( ! $orders ) {
			$orders = wp_list_pluck( $this->query_orders(), 'ID' );
			wp_cache_set( $this->id, $orders, 'llms_tool_data' );
		}

		return $orders;

	}

	/**
	 * Schedules payments and expiration for an order
	 *
	 * Retrieves orders from the `get_orders()` method and schedules a recurring payment
	 * and expiration action based on its existing calculated order data.
	 *
	 * @since 4.6.0
	 * @since 4.7.0 Set `plan_ended` metadata for orders with an ended plan and don't attempt to process them.
	 *
	 * @return int[] Returns an array of WP_Post IDs for orders successfully rescheduled by the method.
	 */
	protected function handle() {

		$orders = array();

		foreach ( $this->get_orders() as $id ) {
			$order = llms_get_post( $id );
			$next  = $order->get_next_payment_due_date();
			if ( is_wp_error( $next ) && 'plan-ended' === $next->get_error_code() ) {
				$order->set( 'plan_ended', 'yes' );
				continue;
			}
			$order->maybe_schedule_payment( false );
			$order->maybe_schedule_expiration();
			if ( $order->get_next_scheduled_action_time( 'llms_charge_recurring_payment' ) ) {
				$orders[] = $id;
			}
		}

		wp_cache_delete( $this->id, 'llms_tool_data' );
		wp_cache_delete( sprintf( '%s-total-results', $this->id ), 'llms_tool_data' );

		return $orders;

	}

	/**
	 * Perform a DB query for orders to be handled by the tool
	 *
	 * @since 4.6.0
	 * @since 4.7.0 Added `SQL_CALC_FOUND_ROWS` and improved query to exclude results with a completed payment plan.
	 * @since 10.0.0 Replaced SQL_CALC_FOUND_ROWS with a separate COUNT(*) query.
	 *
	 * @return object[]
	 */
	protected function query_orders() {

		global $wpdb;

		$from_joins_where = "FROM {$wpdb->posts} AS p
		  LEFT JOIN {$wpdb->postmeta} AS m
			     ON p.ID = m.post_ID
			    AND m.meta_key = '_llms_plan_ended'
		  LEFT JOIN {$wpdb->prefix}actionscheduler_actions AS a
			     ON a.args   = CONCAT( '{\"order_id\":', p.ID, '}' )
			    AND a.hook   = 'llms_charge_recurring_payment'
			    AND a.status = 'pending'
			  WHERE 1
			    AND p.post_type   = 'llms_order'
			    AND p.post_status = 'llms-active'
			    AND a.action_id IS NULL
			    AND m.meta_value IS NULL";

		$total = $wpdb->get_var( "SELECT COUNT(*) {$from_joins_where}" ); // no-cache ok.
		wp_cache_set( sprintf( '%s-total-results', $this->id ), $total, 'llms_tool_data' );

		$orders = $wpdb->get_results(
			"SELECT p.ID
			   {$from_joins_where}
		   ORDER BY p.ID ASC
			  LIMIT 50
			;"
		); // no-cache ok -- Caching implemented in `get_orders()`.

		return $orders;

	}

	/**
	 * Conditionally load the tool
	 *
	 * This tool should only load if there are orders that can be handled by the tool.
	 *
	 * @since 4.6.0
	 *
	 * @return boolean Return `true` to load the tool and `false` to not load it.
	 */
	protected function should_load() {
		return count( $this->get_orders() ) > 0;
	}

}

return new LLMS_Admin_Tool_Recurring_Payment_Rescheduler();
