<?php
declare(strict_types=1);

/**
 * AuditRateLimiter — Per-admin decryption rate limiting for SCLS
 *
 * Enforces a sliding-window rate limit of 10 decryptions per minute per admin.
 * Uses the engine.sec_audit_rate_limits table as the authoritative counter.
 */

if (!defined('DASHBOARD_ROOT')) {
    http_response_code(403);
    exit('Direct access denied.');
}

class AuditRateLimiter
{
    private PDO $engineDb;

    private const MAX_PER_MINUTE = 10;
    private const WINDOW_SECONDS = 60;

    public function __construct(PDO $engineDb)
    {
        $this->engineDb = $engineDb;
    }

    /**
     * Check if admin is under the rate limit.
     *
     * @param  string $adminId  Admin identifier
     * @return bool             True if under limit (allowed), false if exceeded
     */
    public function check(string $adminId): bool
    {
        $windowStart = $this->currentWindowStart();

        $stmt = $this->engineDb->prepare(
            'SELECT request_count
             FROM sec_audit_rate_limits
             WHERE admin_id = ? AND window_start = ?'
        );
        $stmt->execute([$adminId, $windowStart]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return true; // No requests in this window
        }

        return (int)$row['request_count'] < self::MAX_PER_MINUTE;
    }

    /**
     * Increment the rate limit counter for this admin.
     *
     * @param string $adminId  Admin identifier
     */
    public function increment(string $adminId): void
    {
        $windowStart = $this->currentWindowStart();

        $stmt = $this->engineDb->prepare(
            'INSERT INTO sec_audit_rate_limits (admin_id, window_start, request_count, total_lifetime, last_request)
             VALUES (?, ?, 1, 1, NOW())
             ON DUPLICATE KEY UPDATE
                 request_count  = request_count + 1,
                 total_lifetime = total_lifetime + 1,
                 last_request   = NOW()'
        );
        $stmt->execute([$adminId, $windowStart]);
    }

    /**
     * Get rate limit stats for an admin.
     *
     * @param  string $adminId  Admin identifier
     * @return array            {count, limit, window_start, total, last_request, remaining}
     */
    public function getStats(string $adminId): array
    {
        $windowStart = $this->currentWindowStart();

        // Current window count
        $stmt = $this->engineDb->prepare(
            'SELECT request_count, last_request
             FROM sec_audit_rate_limits
             WHERE admin_id = ? AND window_start = ?'
        );
        $stmt->execute([$adminId, $windowStart]);
        $current = $stmt->fetch(PDO::FETCH_ASSOC);

        // Lifetime total
        $stmt2 = $this->engineDb->prepare(
            'SELECT COALESCE(SUM(total_lifetime), 0) AS total,
                    MAX(last_request) AS last_request_ever
             FROM sec_audit_rate_limits
             WHERE admin_id = ?'
        );
        $stmt2->execute([$adminId]);
        $lifetime = $stmt2->fetch(PDO::FETCH_ASSOC);

        $count = $current ? (int)$current['request_count'] : 0;

        return [
            'count'        => $count,
            'limit'        => self::MAX_PER_MINUTE,
            'window_start' => $windowStart,
            'total'        => (int)($lifetime['total'] ?? 0),
            'last_request' => $current['last_request'] ?? $lifetime['last_request_ever'] ?? null,
            'remaining'    => max(0, self::MAX_PER_MINUTE - $count),
        ];
    }

    /**
     * Calculate the start of the current rate-limit window.
     * Floors to the nearest minute boundary.
     */
    private function currentWindowStart(): string
    {
        $ts = time();
        $floored = $ts - ($ts % self::WINDOW_SECONDS);
        return date('Y-m-d H:i:s', $floored);
    }
}
