<?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 );
        // Extract checkout data for enhanced logging (Pro feature).
        $checkout_data = array();
        // 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,
                $checkout_data
            );
            $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.
            $permissive_bypass = 'permissive' === $mode && $detection_context['has_session'];
            if ( $permissive_bypass ) {
                $this->logging_service->log_detection(
                    'classic_ajax',
                    true,
                    array_merge( $detection_context, array(
                        'mode_override' => 'permissive_session_bypass',
                    ) ),
                    $checkout_data
                );
                $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,
                $checkout_data
            );
            $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,
                ) ),
                $checkout_data
            );
            $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,
            $checkout_data
        );
        $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' );
    }

}
