<?php

declare(strict_types=1);

namespace Acms\Services\Setup;

/**
 * セットアップ画面専用の CSRF トークン生成・照合。
 *
 * install フローは DB 未接続の段階を含み、本体の Session::handle()（DB セッション
 * ハンドラや session_write_close 干渉）に依存できないため、setup 独自の native
 * $_SESSION に持たせるトークンをここで扱う。値の保持は呼び出し側（setup.php /
 * install.php のセッション）に委ね、本クラスは生成と照合だけを行う純粋ロジックとする。
 */
final class SetupCsrfToken
{
    /**
     * 新しいトークンを生成する。
     *
     * 本体の CsrfTokenManager::createCsrfToken() と同じく bin2hex(random_bytes(16)) を用い、
     * 暗号論的乱数由来の 32 文字の 16 進文字列を返す。
     */
    public static function generate(): string
    {
        return bin2hex(random_bytes(16));
    }

    /**
     * 期待トークンと入力トークンが一致するか判定する。
     *
     * 空・null は「トークン未発行 / 未送信」であり一致とみなしてはならないため、
     * hash_equals に渡す前に弾く。比較はタイミング攻撃を避けるため hash_equals を使う
     * （=== では文字列長・内容の差で処理時間が変わり得るため）。
     *
     * @param string|null $expected セッションが保持する期待トークン
     * @param string|null $input リクエストで送られてきたトークン
     */
    public static function matches(?string $expected, ?string $input): bool
    {
        if ($expected === null || $expected === '' || $input === null || $input === '') {
            return false;
        }

        return hash_equals($expected, $input);
    }
}
