<?php
/**
 * Database-backed sliding window rate limiter.
 *
 * Used to throttle: public form submissions, unsubscribe attempts,
 * test-email actions, REST endpoints and tracking beacons.
 *
 * @package SuiteMkt3k
 */

namespace SuiteMkt3k\Security;

use SuiteMkt3k\Installer;

defined( 'ABSPATH' ) || exit;
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching

final class Rate_Limiter {

	/**
	 * @param string $scope        Logical bucket (e.g. "public_form", "unsubscribe", "test_email").
	 * @param string $identifier   Already-hashed identifier (IP hash + scope key).
	 * @param int    $max          Maximum hits per window.
	 * @param int    $window_secs  Window length in seconds.
	 * @return bool true if allowed, false if blocked.
	 */
	public static function check( string $scope, string $identifier, int $max, int $window_secs = 60 ): bool {
		global $wpdb;
		$table = Installer::table( 'rate_limits' );
		$now   = current_time( 'mysql', true );
		$cutoff = gmdate( 'Y-m-d H:i:s', time() - $window_secs );

		$wpdb->query(
			$wpdb->prepare(
				'DELETE FROM %i WHERE window_start < %s',
				$table,
				$cutoff
			)
		);

		$row = $wpdb->get_row(
			$wpdb->prepare(
				'SELECT id, counter FROM %i WHERE scope = %s AND identifier = %s',
				$table,
				$scope,
				$identifier
			),
			ARRAY_A
		);

		if ( ! $row ) {
			$wpdb->insert(
				$table,
				array(
					'scope'        => $scope,
					'identifier'   => $identifier,
					'counter'      => 1,
					'window_start' => $now,
				),
				array( '%s', '%s', '%d', '%s' )
			);
			return true;
		}

		if ( (int) $row['counter'] >= $max ) {
			return false;
		}

		$wpdb->update(
			$table,
			array( 'counter' => (int) $row['counter'] + 1 ),
			array( 'id' => (int) $row['id'] ),
			array( '%d' ),
			array( '%d' )
		);
		return true;
	}

	public static function visitor_id(): string {
		$ip = \SuiteMkt3k\Utils\Sanitizer::server( 'REMOTE_ADDR', 'text' );
		$ua = \SuiteMkt3k\Utils\Sanitizer::server( 'HTTP_USER_AGENT', 'text' );
		$ua = substr( $ua, 0, 200 );
		$salt = (string) get_option( 'suitemkt3k_secret_key', '' );
		return hash( 'sha256', $ip . '|' . $ua . '|' . $salt );
	}
}
