<?php
/**
 * Shipment status scheduler.
 *
 * @package PaczkomatyInpost
 */

use Psr\Log\LoggerInterface;
use VendorInPost\WPDesk\PluginBuilder\Plugin\Hookable;

/**
 * Can schedule shipment status refresh.
 */
class WPDesk_Paczkomaty_Shipment_Status_Scheduler implements Hookable {

	const NEXT_SCHEDULE_MULTIPLIER = 5;

	const SCHEDULES_IN_SECONDS = array(
		10,    // 10 sec
		60,    // 1 min
		300,   // 5 min
		3600,  // 1 hour
		21600, // 6 hours
		86400, // 24 hours
	);
	const ACTION_REFRESH_SHIPMENT_STATUS = 'woocommerce_paczkomaty_inpost_refresh_shipment_status';

	/**
	 * @var LoggerInterface
	 */
	private $logger;

	/**
	 * @var WC_Queue_Interface
	 */
	private $queue;

	/**
	 * WPDesk_Paczkomaty_Shipment_Status_Scheduler constructor.
	 *
	 * @param WPDesk_Paczkomaty_Logger $logger .
	 * @param WC_Queue_Interface       $queue .
	 */
	public function __construct( WPDesk_Paczkomaty_Logger $logger, WC_Queue_Interface $queue ) {
		$this->logger = $logger;
		$this->queue = $queue;
	}

	/**
	 * Hooks.
	 */
	public function hooks() {
		add_action( 'woocommerce_paczkomaty_inpost_shipment_created', array( $this, 'schedule_status_refresh_on_shipment_created' ) );
		add_action( self::ACTION_REFRESH_SHIPMENT_STATUS, array( $this, 'refresh_status' ), 10, 3 );
	}

	/**
	 * Schedule status refresh in given next schedule time.
	 *
	 * @param WPDesk_Flexible_Shipping_Shipment_Paczkomaty $shipment .
	 *
	 * @internal
	 */
	public function schedule_status_refresh_on_shipment_created( $shipment ) {
		$this->schedule_status_refresh( $shipment );
	}

	/**
	 * Schedule status refresh in given next schedule time.
	 *
	 * @param WPDesk_Flexible_Shipping_Shipment_Paczkomaty $shipment .
	 * @param int                                          $current_run_number .
	 */
	private function schedule_status_refresh( $shipment, $current_run_number = 0 ) {
		$args = array(
			'shipment_id'        => $shipment->get_id(),
			'inpost_shipment_id' => $shipment->get_meta( $shipment::META_PACZKOMAT_SHIPMENT_ID ),
			'current_run_number' => $current_run_number,
		);
		$schedule_in_seconds = self::SCHEDULES_IN_SECONDS;
		$schedule_time = $this->should_next_schedule( $current_run_number ) ? $schedule_in_seconds[ $current_run_number ] : 0;
		$this->queue->schedule_single( time() + $schedule_time, self::ACTION_REFRESH_SHIPMENT_STATUS, $args, 'woocommerce_paczkomaty_inpost' );
		$this->logger->debug(
			'Inpost status scheduler: scheduled status refresh.',
			array(
				'shipment_id' => $shipment->get_id(),
				'status'      => $shipment->get_status(),
			)
		);
	}

	/**
	 * Should next schedule?
	 * Do not schedule forever. With first schedule in 5 seconds and multiplier 5 status will be refreshed 5 times, in:
	 * 5, 25, 125, 625 and 3125 seconds.
	 *
	 * @param int $current_run_number .
	 *
	 * @return bool
	 */
	private function should_next_schedule( $current_run_number ) {
		$schedule_in_seconds = self::SCHEDULES_IN_SECONDS;
		return isset( $schedule_in_seconds[ $current_run_number ] );
	}


	/**
	 * Schedule next shipment refresh.
	 * Next schedule time is computed as multiply of current schedule time.
	 *
	 * @param WPDesk_Flexible_Shipping_Shipment_Paczkomaty $shipment .
	 * @param int                                          $current_run_number .
	 */
	public function schedule_next_refresh( $shipment, $current_run_number ) {
		if ( $this->should_next_schedule( $current_run_number ) ) {
			$this->schedule_status_refresh( $shipment, $current_run_number + 1 );
		}
	}

	/**
	 * Refresh shipment status.
	 *
	 * @param int    $shipment_id .
	 * @param string $inpost_shipment_id .
	 * @param int    $current_run_number .
	 *
	 * @throws WPDesk_Paczkomaty_ShipX_Exception .
	 *
	 * @internal
	 */
	public function refresh_status( $shipment_id, $inpost_shipment_id, $current_run_number ) {
		$status_refresher = new WPDesk_Paczkomaty_Shipment_Status_Refresher( $shipment_id, $inpost_shipment_id, $current_run_number, $this, $this->logger );
		$status_refresher->refresh_status();
	}

}
