<?php
/**
 * Classic Checkout interceptor for traditional WooCommerce checkout protection.
 *
 * @package Carticy\CheckoutShield\Interceptors
 */

declare(strict_types=1);

namespace Carticy\CheckoutShield\Interceptors;

use Carticy\CheckoutShield\Services\DetectionService;
use Carticy\CheckoutShield\Services\LoggingService;
use Carticy\CheckoutShield\Services\OrderAttributionService;
use Carticy\CheckoutShield\Services\WhitelistService;
use Exception;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Intercepts Classic Checkout requests for bot detection.
 */
final class ClassicCheckoutInterceptor {

	/**
	 * Detection service.
	 *
	 * @var DetectionService
	 */
	private DetectionService $detection_service;

	/**
	 * Logging service.
	 *
	 * @var LoggingService
	 */
	private LoggingService $logging_service;

	/**
	 * Whitelist service.
	 *
	 * @var WhitelistService
	 */
	private WhitelistService $whitelist_service;

	/**
	 * Order attribution service.
	 *
	 * @var OrderAttributionService
	 */
	private OrderAttributionService $attribution_service;

	/**
	 * Constructor.
	 *
	 * @param DetectionService        $detection_service   Detection service instance.
	 * @param LoggingService          $logging_service     Logging service instance.
	 * @param WhitelistService        $whitelist_service   Whitelist service instance.
	 * @param OrderAttributionService $attribution_service Order attribution service instance.
	 */
	public function __construct(
		DetectionService $detection_service,
		LoggingService $logging_service,
		WhitelistService $whitelist_service,
		OrderAttributionService $attribution_service
	) {
		$this->detection_service   = $detection_service;
		$this->logging_service     = $logging_service;
		$this->whitelist_service   = $whitelist_service;
		$this->attribution_service = $attribution_service;
	}

	/**
	 * Register hooks.
	 */
	public function register(): void {
		// Priority 5 to run before WooCommerce's default processing.
		add_action( 'woocommerce_before_checkout_process', array( $this, 'intercept_classic_checkout' ), 5 );
	}

	/**
	 * Intercept classic checkout requests.
	 *
	 * @throws Exception When validation fails (halts checkout immediately).
	 */
	public function intercept_classic_checkout(): void {
		// Check if protection is enabled.
		if ( ! $this->is_enabled() ) {
			return;
		}

		// Check IP whitelist.
		$client_ip = $this->whitelist_service->get_client_ip();
		if ( $this->whitelist_service->is_whitelisted_ip( $client_ip ) ) {
			$this->logging_service->info(
				'Classic checkout request whitelisted',
				array(
					'ip' => $client_ip,
				)
			);
			$this->attribution_service->set_attribution( 'classic_ajax', 'bypassed', array( 'reason' => 'whitelisted' ) );
			return;
		}

		// Validate double-submit.
		$validation_passed = $this->detection_service->validate_double_submit();
		$detection_context = $this->detection_service->get_detection_context( $validation_passed );

		// Get current mode.
		$mode = $this->get_mode();

		// Learning mode: log but don't block.
		if ( 'learning' === $mode ) {
			$this->logging_service->log_detection( 'classic_ajax', $validation_passed, $detection_context );
			$this->attribution_service->set_attribution( 'classic_ajax', 'learning', $detection_context );
			return;
		}

		// Handle based on mode.
		if ( ! $validation_passed ) {
			// Permissive mode: only block if no session exists.
			if ( 'permissive' === $mode && $detection_context['has_session'] ) {
				$this->logging_service->log_detection(
					'classic_ajax',
					true,
					array_merge(
						$detection_context,
						array( 'mode_override' => 'permissive_session_bypass' )
					)
				);
				$this->attribution_service->set_attribution(
					'classic_ajax',
					'passed',
					array_merge(
						$detection_context,
						array( 'mode_override' => 'permissive_session_bypass' )
					)
				);
				return;
			}

			// Block the request.
			$this->logging_service->log_detection( 'classic_ajax', false, $detection_context );
			$this->attribution_service->set_attribution( 'classic_ajax', 'blocked', $detection_context );
			$this->block_checkout();
		}

		// Strict mode: also require session.
		if ( 'strict' === $mode && ! $detection_context['has_session'] ) {
			$this->logging_service->log_detection(
				'classic_ajax',
				false,
				array_merge(
					$detection_context,
					array( 'strict_session_required' => true )
				)
			);
			$this->attribution_service->set_attribution(
				'classic_ajax',
				'blocked',
				array_merge(
					$detection_context,
					array( 'strict_session_required' => true )
				)
			);
			$this->block_checkout();
		}

		// Validation passed.
		$this->logging_service->log_detection( 'classic_ajax', true, $detection_context );
		$this->attribution_service->set_attribution( 'classic_ajax', 'passed', $detection_context );
	}

	/**
	 * Block the checkout with an error message.
	 *
	 * @throws Exception Always throws to halt checkout immediately.
	 */
	private function block_checkout(): void {
		// Add user-facing error notice.
		wc_add_notice(
			__( 'Unable to process your request. Please refresh the page and try again.', 'carticy-checkout-shield-for-woocommerce' ),
			'error'
		);

		// Throw exception to halt checkout immediately.
		// WooCommerce catches this gracefully and displays the error.
		throw new Exception(
			esc_html__( 'Security validation failed.', 'carticy-checkout-shield-for-woocommerce' )
		);
	}

	/**
	 * Check if protection is enabled.
	 *
	 * @return bool
	 */
	private function is_enabled(): bool {
		return get_option( 'carticy_checkout_shield_enabled', 'yes' ) === 'yes';
	}

	/**
	 * Get the current operating mode.
	 *
	 * @return string
	 */
	private function get_mode(): string {
		$mode = get_option( 'carticy_checkout_shield_mode', 'balanced' );
		return in_array( $mode, array( 'learning', 'permissive', 'balanced', 'strict' ), true ) ? $mode : 'balanced';
	}
}
