<?php

declare(strict_types=1);

namespace BotGuard\Middleware;

use BotGuard\Core\Csrf;
use BotGuard\Core\Exceptions\HttpException;
use BotGuard\Core\Request;
use BotGuard\Core\Response;
use Closure;

/**
 * Verifies a CSRF token on every state-changing request (POST/PUT/PATCH/DELETE).
 *
 * The token is read from the `_csrf` form field, the `X-CSRF-Token` header or a
 * JSON `_csrf` field, and compared with the session token in constant time.
 */
final class CsrfMiddleware implements MiddlewareInterface
{
    private const SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS'];

    public function __construct(private Csrf $csrf)
    {
    }

    public function handle(Request $request, Closure $next): Response
    {
        if (in_array($request->method(), self::SAFE_METHODS, true)) {
            return $next($request);
        }

        $token = $request->header('X-CSRF-Token')
            ?? $request->input('_csrf');

        if (! $this->csrf->validate(is_string($token) ? $token : null)) {
            throw new HttpException(419, 'CSRF token mismatch. Please refresh and try again.');
        }

        return $next($request);
    }
}
