<?php

namespace App\Http\Middleware;

use Closure;
use cPad\Plugins\Forum\Services\Security\BotProtectionService;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\Request;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Symfony\Component\HttpFoundation\Response;

class ForumRateLimitMiddleware
{
    public function __construct(
        private readonly ThrottleRequests $throttleRequests,
        private readonly BotProtectionService $botProtectionService,
    ) {
    }

    public function handle(Request $request, Closure $next): Response
    {
        $routeName = (string) optional($request->route())->getName();
        $limiterName = match ($routeName) {
            'forum.topic.store' => 'forum-thread-create',
            default => 'forum-post-write',
        };

        try {
            return $this->throttleRequests->handle($request, $next, $limiterName);
        } catch (ThrottleRequestsException $exception) {
            $maxAttempts = (int) ($exception->getHeaders()['X-RateLimit-Limit'] ?? 0);

            $this->botProtectionService->recordRateLimitViolation(
                $request,
                $this->resolveActionName($routeName),
                [
                    'limiter' => $limiterName,
                    'bucket' => $this->resolveBucket($limiterName, $maxAttempts),
                    'max_attempts' => $maxAttempts,
                    'retry_after' => (int) ($exception->getHeaders()['Retry-After'] ?? 0),
                    'reason' => sprintf('Forum write rate limit exceeded on %s.', $routeName !== '' ? $routeName : 'unknown route'),
                ],
            );

            throw $exception;
        }
    }

    private function resolveActionName(string $routeName): string
    {
        return match ($routeName) {
            'forum.topic.store' => 'forum_topic_create',
            'forum.post.update' => 'forum_post_update',
            default => 'forum_reply_create',
        };
    }

    private function resolveBucket(string $limiterName, int $maxAttempts): string
    {
        return $maxAttempts <= $this->minuteLimitThreshold($limiterName) ? 'minute' : 'hour';
    }

    private function minuteLimitThreshold(string $limiterName): int
    {
        return match ($limiterName) {
            'forum-thread-create', 'forum-post-write' => 3,
            default => PHP_INT_MAX,
        };
    }
}
