<?php
/**
 * Recovery Action Handler for Cart Recovery
 *
 * Handles cart restoration and unsubscribe actions triggered via
 * query parameters with comprehensive security validation.
 *
 * @package EDD\Pro\CartRecovery\Handlers
 * @copyright Copyright (c) 2026, Sandhills Development, LLC
 * @license https://opensource.org/licenses/GPL-2.0 GNU Public License
 * @since   3.6.5
 */

declare(strict_types=1);

namespace EDD\Pro\CartRecovery\Handlers;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore

use EDD\Cache\NoCache;
use EDD\Utils\Validators\RateLimiter;
use EDD\Pro\CartRecovery\Config\Security;
use EDD\Pro\CartRecovery\Services\Restore;
use EDD\Pro\CartRecovery\Services\Unsubscribe;

/**
 * Recovery Action Handler class.
 *
 * Processes recovery actions with security validation, rate limiting,
 * and user feedback via EDD's session-based notice system.
 */
class Recovery {

	/**
	 * Rate limiter instance.
	 *
	 * @var RateLimiter
	 */
	private RateLimiter $rate_limiter;

	/**
	 * Constructor.
	 *
	 * @since 3.6.5
	 */
	public function __construct() {
		$window             = (int) Security::get_restore_rate_window();
		$window             = $window > 0 ? $window : HOUR_IN_SECONDS;
		$limit              = (int) Security::get_restore_rate_limit();
		$limit              = $limit > 0 ? $limit : 5;
		$this->rate_limiter = new RateLimiter( 'edd_acr_restore_rate', $limit, $window );
	}

	/**
	 * Handles recovery actions triggered via query parameters.
	 *
	 * @since 3.6.5
	 * @param array $data The data passed to the event.
	 * @return void
	 */
	public function handle_recovery_actions( array $data ): void {

		// Sanitize and extract action and token from request.
		$action = sanitize_key( wp_unslash( $data['edd_action'] ) );
		$token  = isset( $data['token'] ) ? sanitize_text_field( wp_unslash( $data['token'] ) ) : '';

		// Apply rate limiting to restore and unsubscribe actions.
		if ( in_array( $action, array( 'cart_recovery_restore', 'cart_recovery_unsubscribe' ), true ) ) {
			NoCache::set_headers();
			$client_ip = edd_get_ip();
			$client_ip = is_string( $client_ip ) ? $client_ip : 'unknown';
			if ( empty( $client_ip ) || 'unknown' === $client_ip ) {
				$this->handle_error( 'edd_acr_restore_failed', __( 'Unable to determine client IP for rate limiting.', 'easy-digital-downloads' ) );
				return;
			}

			$rate_limit_result = $this->rate_limiter->check( $client_ip );
			if ( is_wp_error( $rate_limit_result ) ) {
				if ( edd_is_debug_mode() && edd_is_test_mode() ) {
					\EDD\Utils\Messages::add( 'warning', 'rate_limit_exceeded', $rate_limit_result->get_error_message() );
				} else {
					$this->handle_error( 'edd_acr_restore_failed', $rate_limit_result->get_error_message() );
					return;
				}
			}
		}

		// Validate token presence before processing.
		if ( empty( $token ) ) {
			$this->handle_error( 'edd_acr_restore_failed', __( 'Your recovery link is missing the token.', 'easy-digital-downloads' ) );
		}

		// Process cart restoration action.
		if ( 'cart_recovery_restore' === $action ) {
			$service = new Restore();
			$result  = $service->restore( $token );

			if ( is_wp_error( $result ) ) {
				$this->handle_error( $result->get_error_code(), $result->get_error_message() );
			}

			edd_set_success( 'edd_acr_restored', __( 'We rebuilt your cart. You can continue your checkout.', 'easy-digital-downloads' ) );
			edd_redirect( edd_get_checkout_uri() );
		}

		// Process unsubscribe action.
		if ( 'cart_recovery_unsubscribe' === $action ) {
			$service = new Unsubscribe();
			$result  = $service->unsubscribe( $token );

			if ( is_wp_error( $result ) ) {
				$this->handle_error( $result->get_error_code(), $result->get_error_message() );
			}

			\EDD\Utils\Messages::add( 'info', 'edd_acr_unsubscribed', __( 'You have been unsubscribed from future recovery emails.', 'easy-digital-downloads' ) );
			edd_redirect( edd_get_checkout_uri() );
		}
	}

	/**
	 * Handles an error.
	 *
	 * @since 3.6.5
	 * @param string $code The error code.
	 * @param string $message The error message.
	 * @return void
	 */
	private function handle_error( string $code, string $message ): void {
		edd_set_error( $code, $message );
		edd_debug_log( '[ACR] ' . $message );
		edd_redirect( edd_get_checkout_uri() );
	}
}
