<?php

declare(strict_types=1);

function rate_limit_path(string $key): string
{
    return runtime_path('cache/rate/' . sha1($key) . '.json');
}

function rate_limit_check(string $bucket, int $maxRequests, int $windowSeconds = 60): array
{
    $maxRequests = max(1, $maxRequests);
    $windowSeconds = max(1, $windowSeconds);

    $path = rate_limit_path($bucket);
    $handle = fopen($path, 'c+');

    if ($handle === false) {
        return [
            'allowed' => true,
            'remaining' => $maxRequests,
            'retry_after' => 0,
        ];
    }

    flock($handle, LOCK_EX);

    $raw = stream_get_contents($handle);
    $state = ['window_start' => time(), 'count' => 0];

    if ($raw !== false && trim($raw) !== '') {
        $decoded = json_decode($raw, true);
        if (is_array($decoded)) {
            $state['window_start'] = (int) ($decoded['window_start'] ?? time());
            $state['count'] = (int) ($decoded['count'] ?? 0);
        }
    }

    $now = time();
    $elapsed = $now - $state['window_start'];

    if ($elapsed >= $windowSeconds) {
        $state['window_start'] = $now;
        $state['count'] = 0;
        $elapsed = 0;
    }

    $allowed = $state['count'] < $maxRequests;

    if ($allowed) {
        $state['count']++;
    }

    $remaining = max(0, $maxRequests - $state['count']);
    $retryAfter = max(0, $windowSeconds - $elapsed);

    ftruncate($handle, 0);
    rewind($handle);
    fwrite($handle, json_encode($state));

    flock($handle, LOCK_UN);
    fclose($handle);

    return [
        'allowed' => $allowed,
        'remaining' => $remaining,
        'retry_after' => $retryAfter,
    ];
}