<?php

declare(strict_types=1);

namespace SiteFort\Modules\Firewall;

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

use SiteFort\Includes\ProxyPresets;

final class ProtectedNetworkGuard {

	/**
	 * @var string[]|null
	 */
	private static ?array $cloudflare_ranges = null;

	/**
	 * @return array{code:string,message:string,matched_rule:string}|null
	 */
	public static function describe_block_rejection( string $entry ): ?array {
		$normalized = self::normalize_entry( $entry );
		if ( $normalized === null ) {
			return null;
		}

		$matched_range = self::find_overlap( $normalized, self::get_cloudflare_ranges() );
		if ( $matched_range !== null ) {
			return [
				'code'         => 'protected_cloudflare_proxy',
				'message'      => sprintf(
					'This entry overlaps Cloudflare proxy range %s and cannot be blocked. SiteFort must inspect the real visitor IP behind Cloudflare instead.',
					$matched_range
				),
				'matched_rule' => $matched_range,
			];
		}

		return null;
	}

	/**
	 * @param string[] $entries
	 * @return array{allowed:string[],skipped:array<int,array{entry:string,matched_rule:string}>}
	 */
	public static function filter_block_entries( array $entries ): array {
		$allowed = [];
		$skipped = [];

		foreach ( $entries as $entry ) {
			$value = (string) $entry;
			$rejection = self::describe_block_rejection( $value );
			if ( $rejection !== null ) {
				$skipped[] = [
					'entry'        => $value,
					'matched_rule' => $rejection['matched_rule'],
				];
				continue;
			}

			$normalized = self::normalize_entry( $value );
			if ( $normalized !== null ) {
				$allowed[] = $normalized;
			}
		}

		return [
			'allowed' => array_values( array_unique( $allowed ) ),
			'skipped' => $skipped,
		];
	}

	/**
	 * @return string[]
	 */
	private static function get_cloudflare_ranges(): array {
		if ( self::$cloudflare_ranges !== null ) {
			return self::$cloudflare_ranges;
		}

		self::$cloudflare_ranges = RuleEngine::normalize_ip_entries(
			ProxyPresets::get_ranges( ProxyPresets::PRESET_CLOUDFLARE ),
			false
		);

		return self::$cloudflare_ranges;
	}

	private static function normalize_entry( string $entry ): ?string {
		$normalized = RuleEngine::normalize_ip_entries( [ $entry ], true );
		return ! empty( $normalized ) ? (string) $normalized[0] : null;
	}

	/**
	 * @param string[] $entries
	 */
	private static function find_overlap( string $entry, array $entries ): ?string {
		foreach ( $entries as $candidate ) {
			$value = (string) $candidate;
			if ( RuleEngine::ip_entries_overlap( $entry, $value ) ) {
				return $value;
			}
		}

		return null;
	}
}
