<?php

namespace WPSN\Core;

defined('ABSPATH') || exit;

/**
 * Tiny transient-backed rate limiter (best-effort).
 *
 * Uses a sliding window of timestamps.
 */
final class RateLimiter
{
    /**
     * @return array{allowed: bool, retry_after: int, remaining: int, limit: int}
     */
    public function hit(string $key, int $limit, int $windowSeconds): array
    {
        $key = sanitize_key($key);
        $limit = max(0, (int) $limit);
        $windowSeconds = max(1, (int) $windowSeconds);

        if ($key === '' || $limit === 0) {
            return [
                'allowed' => true,
                'retry_after' => 0,
                'remaining' => $limit,
                'limit' => $limit,
            ];
        }

        $now = time();
        $cutoff = $now - $windowSeconds;

        $timestamps = get_transient($key);
        if (!is_array($timestamps)) {
            $timestamps = [];
        }

        // Purge old timestamps.
        $filtered = [];
        foreach ($timestamps as $t) {
            $tt = (int) $t;
            if ($tt > $cutoff) {
                $filtered[] = $tt;
            }
        }
        $timestamps = $filtered;

        if (count($timestamps) >= $limit) {
            $oldest = min($timestamps);
            $retry = (int) (($oldest + $windowSeconds) - $now);
            if ($retry < 1) {
                $retry = 1;
            }

            // Keep the window alive.
            set_transient($key, $timestamps, $windowSeconds);

            return [
                'allowed' => false,
                'retry_after' => $retry,
                'remaining' => 0,
                'limit' => $limit,
            ];
        }

        $timestamps[] = $now;
        set_transient($key, $timestamps, $windowSeconds);

        return [
            'allowed' => true,
            'retry_after' => 0,
            'remaining' => max(0, $limit - count($timestamps)),
            'limit' => $limit,
        ];
    }
}
