<?php

namespace App\Services\Wireguard;

use BaconQrCode\Common\ErrorCorrectionLevel;
use BaconQrCode\Encoder\Encoder;

/**
 * Renders a WireGuard config as a QR code the mobile apps can scan.
 *
 * Hand-rolled SVG rather than Bacon's renderer: that one needs the imagick or
 * GD backend for images, and its SVG writer pulls in a dependency chain we do
 * not otherwise need. The matrix is the only interesting part, and Bacon gives
 * us that directly.
 */
final class QrCode
{
    public static function svg(string $text, int $size = 220): string
    {
        // Level L: a WireGuard config is long, and the phone is held still
        // against a screen — more redundancy would only make the code denser.
        $matrix = Encoder::encode($text, ErrorCorrectionLevel::L())->getMatrix();
        $width = $matrix->getWidth();
        // Four modules is the specified minimum quiet zone. Less than that and
        // some readers fail to find the symbol at all against a bordered card.
        $quiet = 4;
        $total = $width + 2 * $quiet;

        $cells = '';
        for ($y = 0; $y < $width; $y++) {
            for ($x = 0; $x < $width; $x++) {
                if ($matrix->get($x, $y) === 1) {
                    $cells .= sprintf('<rect x="%d" y="%d" width="1" height="1"/>', $x + $quiet, $y + $quiet);
                }
            }
        }

        return sprintf(
            '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 %1$d %1$d" width="%2$d" height="%2$d" shape-rendering="crispEdges" role="img">'
            .'<rect width="%1$d" height="%1$d" fill="#ffffff"/><g fill="#000000">%3$s</g></svg>',
            $total,
            $size,
            $cells,
        );
    }
}
