<?php

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedNamespaceFound -- APD is the established namespace shared with the Pro add-on and retained for backward compatibility.
namespace APD\Domain\Upload;

use APD\Support\RequestData;
use WP_REST_Request;

defined('ABSPATH') || exit;

final class RuntimeUploadRateLimiter
{
    public function consume(WP_REST_Request $request) : array
    {
        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- The apd_ hook is a documented integration API retained for backward compatibility.
        $limit = max(0, (int) apply_filters('apd_runtime_upload_rate_limit', 30, $request));
        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- The apd_ hook is a documented integration API retained for backward compatibility.
        $window = max(60, (int) apply_filters('apd_runtime_upload_rate_window', 10 * MINUTE_IN_SECONDS, $request));
        if ($limit === 0) {
            return ['allowed' => true, 'retryAfter' => 0];
        }

        $now = time();
        $key = 'apd_upload_rate_' . substr(hash_hmac('sha256', $this->clientIdentifier(), wp_salt('auth')), 0, 32);
        $bucket = get_transient($key);
        $bucket = is_array($bucket) ? $bucket : [];
        $resetAt = isset($bucket['resetAt']) ? (int) $bucket['resetAt'] : 0;
        $count = isset($bucket['count']) ? (int) $bucket['count'] : 0;

        if ($resetAt <= $now) {
            $resetAt = $now + $window;
            $count = 0;
        }

        if ($count >= $limit) {
            return [
                'allowed' => false,
                'retryAfter' => max(1, $resetAt - $now),
            ];
        }

        set_transient($key, [
            'count' => $count + 1,
            'resetAt' => $resetAt,
        ], max(1, $resetAt - $now));

        return ['allowed' => true, 'retryAfter' => 0];
    }

    private function clientIdentifier() : string
    {
        $userId = get_current_user_id();
        if ($userId > 0) {
            return 'user:' . $userId;
        }

        $server = RequestData::server();
        $remoteAddress = filter_var((string) ($server['REMOTE_ADDR'] ?? ''), FILTER_VALIDATE_IP);
        return 'guest:' . (is_string($remoteAddress) ? $remoteAddress : 'unknown');
    }
}
