<?php

declare(strict_types=1);

namespace BotGuard\Core;

/**
 * CSRF token manager.
 *
 * A per-session token is generated and compared using hash_equals to prevent
 * cross-site request forgery on all state-changing requests. The token is
 * surfaced to forms via a hidden field and to AJAX via a meta tag / header.
 */
final class Csrf
{
    private const KEY = '__csrf_token';

    public function __construct(private Session $session)
    {
    }

    /**
     * Return the current token, generating one if needed.
     */
    public function token(): string
    {
        $token = $this->session->get(self::KEY);

        if (! is_string($token) || $token === '') {
            $token = str_random(32);
            $this->session->put(self::KEY, $token);
        }

        return $token;
    }

    /**
     * Validate a supplied token against the session token.
     */
    public function validate(?string $supplied): bool
    {
        $token = $this->session->get(self::KEY);

        return is_string($token) && is_string($supplied) && $supplied !== ''
            && hash_equals($token, $supplied);
    }

    /**
     * Hidden input markup for HTML forms.
     */
    public function field(): string
    {
        return '<input type="hidden" name="_csrf" value="' . e($this->token()) . '">';
    }
}
