<?php

/**
 * Store API interceptor for Block 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 WP_Error;
use WP_REST_Request;
use WP_REST_Server;
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Intercepts Store API checkout requests for bot detection.
 */
final class StoreApiInterceptor {
    /**
     * 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 {
        add_filter(
            'rest_pre_dispatch',
            array($this, 'intercept_store_api'),
            10,
            3
        );
    }

    /**
     * Intercept Store API checkout requests.
     *
     * @param mixed           $result  Response to replace the requested version with.
     * @param WP_REST_Server  $server  Server instance.
     * @param WP_REST_Request $request Request used to generate the response.
     * @return mixed|WP_Error
     */
    public function intercept_store_api( $result, WP_REST_Server $server, WP_REST_Request $request ) {
        // Only intercept Store API checkout POST requests.
        $route = $request->get_route();
        if ( !$this->is_checkout_route( $route ) ) {
            return $result;
        }
        if ( $request->get_method() !== 'POST' ) {
            return $result;
        }
        // Check if protection is enabled.
        if ( !$this->is_enabled() ) {
            return $result;
        }
        // Check whitelist first (API key or IP).
        if ( $this->whitelist_service->is_whitelisted( $request ) ) {
            $this->logging_service->info( 'Store API request whitelisted', array(
                'route' => $route,
                'ip'    => $this->whitelist_service->get_client_ip(),
            ) );
            $this->attribution_service->set_attribution( 'store_api', 'bypassed', array(
                'reason' => 'whitelisted',
            ) );
            return $result;
        }
        // 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(
                'store_api',
                $validation_passed,
                $detection_context,
                $checkout_data
            );
            $this->attribution_service->set_attribution( 'store_api', 'learning', $detection_context );
            return $result;
        }
        // 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(
                    'store_api',
                    true,
                    array_merge( $detection_context, array(
                        'mode_override' => 'permissive_session_bypass',
                    ) ),
                    $checkout_data
                );
                $this->attribution_service->set_attribution( 'store_api', 'passed', array_merge( $detection_context, array(
                    'mode_override' => 'permissive_session_bypass',
                ) ) );
                return $result;
            }
            // Block the request.
            $this->logging_service->log_detection(
                'store_api',
                false,
                $detection_context,
                $checkout_data
            );
            $this->attribution_service->set_attribution( 'store_api', 'blocked', $detection_context );
            return new WP_Error('ccs_blocked', __( 'Unable to process your request. Please refresh the page and try again.', 'carticy-checkout-shield-for-woocommerce' ), array(
                'status' => 403,
            ));
        }
        // Strict mode: also require session.
        if ( 'strict' === $mode && !$detection_context['has_session'] ) {
            $this->logging_service->log_detection(
                'store_api',
                false,
                array_merge( $detection_context, array(
                    'strict_session_required' => true,
                ) ),
                $checkout_data
            );
            $this->attribution_service->set_attribution( 'store_api', 'blocked', array_merge( $detection_context, array(
                'strict_session_required' => true,
            ) ) );
            return new WP_Error('ccs_blocked', __( 'Unable to process your request. Please refresh the page and try again.', 'carticy-checkout-shield-for-woocommerce' ), array(
                'status' => 403,
            ));
        }
        // Validation passed.
        $this->logging_service->log_detection(
            'store_api',
            true,
            $detection_context,
            $checkout_data
        );
        $this->attribution_service->set_attribution( 'store_api', 'passed', $detection_context );
        return $result;
    }

    /**
     * Check if route is a checkout route.
     *
     * @param string $route The REST route.
     * @return bool
     */
    private function is_checkout_route( string $route ) : bool {
        // Match /wc/store/checkout and /wc/store/v1/checkout.
        return (bool) preg_match( '#^/wc/store(/v\\d+)?/checkout#', $route );
    }

    /**
     * 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' );
    }

}
