<?php

declare(strict_types=1);

namespace SiteFort\Modules\Firewall;

use SiteFort\Modules\Firewall\Blocklist\BlocklistService;
use SiteFort\Modules\Firewall\GeoIP\CountryBlocker;

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

final class RequestEvaluator {
	private array $policy;

	private ?BlocklistService $blocklist_service;

	private ?CountryBlocker $country_blocker;

	private ?SensitivePathDetector $sensitive_path_detector;

	public function __construct(
		array $policy,
		?BlocklistService $blocklist_service = null,
		?CountryBlocker $country_blocker = null,
		?SensitivePathDetector $sensitive_path_detector = null
	) {
		$this->policy = $policy;
		$this->blocklist_service = $blocklist_service;
		$this->country_blocker = $country_blocker;
		$this->sensitive_path_detector = $sensitive_path_detector;
	}

	/**
	 * @return array<string, mixed>
	 */
	public function evaluate( string $ip, string $user_agent, array $request_context = [] ): array {
		$country_code = '';
		$country_lookup_performed = false;
		$community_blocked = false;
		$sensitive_path_match = false;
		$verified_search_exception = ! empty( $request_context['verified_search_exception'] );
		$skip_expensive_checks = RuleEngine::find_ip_match( $ip, (array) ( $this->policy['allowlisted_ips'] ?? [] ) ) !== null
			|| RuleEngine::find_user_agent_pattern_match( $user_agent, (array) ( $this->policy['trusted_user_agents'] ?? [] ) ) !== null;
		$skip_country_and_blocklist_checks = $skip_expensive_checks || $verified_search_exception;

		if ( ! $skip_country_and_blocklist_checks && $this->country_blocker ) {
			$country = $this->country_blocker->should_block( $ip );
			$country_code = strtoupper( trim( (string) ( $country['country_code'] ?? '' ) ) );
			$country_lookup_performed = ! empty( $country['lookup_performed'] );
		}

		if ( ! $skip_country_and_blocklist_checks && $this->blocklist_service ) {
			$community_blocked = $this->blocklist_service->is_blocked( $ip );
		}

		if ( ! $skip_expensive_checks && $this->sensitive_path_detector ) {
			$sensitive_path_match = $this->sensitive_path_detector->matches_request();
		}

		return RuleEngine::evaluate(
			$this->policy,
			[
				'ip' => $ip,
				'user_agent' => $user_agent,
				'country_code' => $country_code,
				'country_lookup_performed' => $country_lookup_performed,
				'community_blocked' => $community_blocked,
				'sensitive_path_match' => $sensitive_path_match,
				'verified_search_exception' => $verified_search_exception,
				'verified_search_engine' => (string) ( $request_context['verified_search_engine'] ?? '' ),
			]
		);
	}
}
