<?php

declare(strict_types=1);

namespace SiteFort\Modules\Firewall;

use SiteFort\Includes\IpDetector;

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

class IpBlocking {
	private array $settings;

	private ?array $allowlisted_entries_cache = null;
	private ?array $active_banned_entries_cache = null;
	private array $is_allowed_cache = [];

	public function __construct( array $settings ) {
		$this->settings = FirewallSettings::sanitize( $settings );
	}

	/**
	 * @return array<int, string>
	 */
	public function get_allowlisted_entries(): array {
		if ( $this->allowlisted_entries_cache !== null ) {
			return $this->allowlisted_entries_cache;
		}

		$this->allowlisted_entries_cache = RuleEngine::normalize_ip_entries( (string) ( $this->settings['allowlist'] ?? '' ), true );
		return $this->allowlisted_entries_cache;
	}

	/**
	 * @return array<int, string>
	 */
	public function get_active_banned_entries(): array {
		if ( $this->active_banned_entries_cache !== null ) {
			return $this->active_banned_entries_cache;
		}

		$manager = new LockoutManager();
		if ( $manager->purge_expired_if_due() > 0 ) {
			$this->settings = FirewallSettings::sanitize( FirewallSettings::get() );
		}

		$this->active_banned_entries_cache = RuleEngine::normalize_ip_entries( (string) ( $this->settings['banned_ips'] ?? '' ), true );
		return $this->active_banned_entries_cache;
	}

	public function is_allowed( string $ip ): bool {
		if ( array_key_exists( $ip, $this->is_allowed_cache ) ) {
			return $this->is_allowed_cache[ $ip ];
		}

		$this->is_allowed_cache[ $ip ] = RuleEngine::find_ip_match( $ip, $this->get_allowlisted_entries() ) !== null;
		return $this->is_allowed_cache[ $ip ];
	}

	public function block_request( string $message, string $reason ): void {
		do_action( 'sitefort_firewall_block', [
			'site_url' => home_url(),
			'ip' => IpDetector::get_ip(),
			'attack_type' => $reason,
			'request_uri' => IpDetector::get_server_value( 'REQUEST_URI' ),
		] );

		if ( ! headers_sent() ) {
			http_response_code( 403 );
			header( 'Content-Type: text/html; charset=UTF-8' );
			header( 'Cache-Control: no-store, no-cache, must-revalidate, max-age=0' );
		}

		require_once __DIR__ . '/block-page.php';
		sitefort_render_block_page( 403, $message, IpDetector::get_ip() );
		exit;
	}
}
