<?php
/**
 * @package Hafenstudios\Wellenbrecher
 */

namespace Hafenstudios\Wellenbrecher\Rules;

use Hafenstudios\Wellenbrecher\Engine\Context;
use Hafenstudios\Wellenbrecher\Engine\RuleResult;
use Hafenstudios\Wellenbrecher\Support\IpHasher;

defined( 'ABSPATH' ) || exit;

/**
 * Rate-Limit ueberschritten: mehr als N Submits pro Fenster je IP-HMAC und
 * Kanal (Transient-Zaehler). Die IP wird nur als HMAC verarbeitet; der
 * Transient-Schluessel enthaelt nie Klartext.
 */
class RateLimitRule extends AbstractRule {

	public const ID             = 'rate_limit';
	public const DEFAULT_POINTS = 25;

	public const DEFAULT_MAX    = 5;
	public const DEFAULT_WINDOW = 60;

	protected IpHasher $hasher;

	protected int $max;

	protected int $window;

	/**
	 * @param IpHasher $hasher IP-HMAC-Helfer.
	 * @param int      $points Punkte.
	 * @param int      $max    Erlaubte Submits pro Fenster.
	 * @param int      $window Fensterlaenge in Sekunden.
	 */
	public function __construct( IpHasher $hasher, int $points = self::DEFAULT_POINTS, int $max = self::DEFAULT_MAX, int $window = self::DEFAULT_WINDOW ) {
		parent::__construct( $points );
		$this->hasher = $hasher;
		$this->max    = max( 1, $max );
		$this->window = max( 1, $window );
	}

	public function id(): string {
		return self::ID;
	}

	public function stage(): int {
		return 1;
	}

	public function evaluate( Context $context ): RuleResult {
		$ip = $context->server( 'remote_addr' );
		if ( '' === $ip ) {
			return $this->miss();
		}

		$key   = 'wb_rate_' . md5( $context->channel . '|' . $this->hasher->hash( $ip ) );
		$count = (int) get_transient( $key );
		set_transient( $key, $count + 1, $this->window );

		return $count >= $this->max ? $this->hit() : $this->miss();
	}
}
