<?php

namespace CaptureRelay;

use WP_Error;

final class RateLimiter
{
    public static function hit(string $bucket, int $limit, int $window = HOUR_IN_SECONDS): true|WP_Error
    {
        global $wpdb;
        $bucketHash = hash('sha256', $bucket);
        $now = current_time('mysql', true);
        $expires = gmdate('Y-m-d H:i:s', time() + max(1, $window));
        $result = $wpdb->query($wpdb->prepare(
            'INSERT INTO %i (bucket_hash, hit_count, window_started_at, expires_at) VALUES (%s, 1, %s, %s) '
            . 'ON DUPLICATE KEY UPDATE hit_count = IF(expires_at < VALUES(window_started_at), 1, hit_count + 1), '
            . 'window_started_at = IF(expires_at < VALUES(window_started_at), VALUES(window_started_at), window_started_at), '
            . 'expires_at = IF(expires_at < VALUES(window_started_at), VALUES(expires_at), expires_at)',
            Config::table('rate_limits'),
            $bucketHash,
            $now,
            $expires
        ));
        if ($result === false) {
            Log::write('rate_limit_storage_failed', 'The persistent rate limiter could not update its counter.', [], 'error');
            return new WP_Error('capture_relay_rate_limit_unavailable', __('Request protection is temporarily unavailable. Please try again later.', 'capture-relay'), ['status' => 503]);
        }
        $count = (int) $wpdb->get_var($wpdb->prepare(
            'SELECT hit_count FROM %i WHERE bucket_hash = %s',
            Config::table('rate_limits'),
            $bucketHash
        ));
        if ($count > max(1, $limit)) {
            Log::write('rate_limit', 'A request was blocked by rate limiting.', ['bucket_hash' => hash('sha256', $bucket)], 'warning');
            return new WP_Error('capture_relay_rate_limited', __('Too many requests. Please try again later.', 'capture-relay'), ['status' => 429]);
        }
        return true;
    }
}
