<?php

namespace App\Services\QrCode;

use App\Enums\QrRenderFormat;
use App\Models\QrCode;
use App\Models\QrCodeRender;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\Writer\PngWriter;
use Endroid\QrCode\Writer\SvgWriter;
use Endroid\QrCode\Writer\WriterInterface;

/**
 * Renders a {@see QrCode} model to raw image bytes via `endroid/qr-code` v6.
 */
class QrImageRenderer
{
    /**
     * Default rendered size, in pixels, when none is given.
     */
    private const DEFAULT_SIZE = 512;

    /**
     * Default margin, in pixels, when none is given.
     */
    private const DEFAULT_MARGIN = 10;

    public function __construct(private readonly QrPayloadBuilder $payloadBuilder)
    {
        //
    }

    /**
     * Render the QR code to raw bytes, logging a {@see QrCodeRender} row.
     *
     * Uses Quartile error correction when a logo is embedded — a logo
     * occludes modules, and low error correction plus a logo produces an
     * unscannable code — and Medium otherwise.
     *
     * @return array{bytes: string, mimeType: string}
     */
    public function render(
        QrCode $qrCode,
        QrRenderFormat $format,
        int $size = self::DEFAULT_SIZE,
        int $margin = self::DEFAULT_MARGIN,
        ?string $logoPath = null,
        ?string $ipAddress = null,
    ): array {
        $builder = new Builder(
            writer: $this->writerFor($format),
            data: $this->payloadBuilder->build($qrCode),
            errorCorrectionLevel: $logoPath !== null ? ErrorCorrectionLevel::Quartile : ErrorCorrectionLevel::Medium,
            size: $size,
            margin: $margin,
            logoPath: $logoPath ?? '',
        );

        $result = $builder->build();

        QrCodeRender::query()->create([
            'qr_code_id' => $qrCode->id,
            'format' => $format,
            'ip_address' => $ipAddress,
        ]);

        return [
            'bytes' => $result->getString(),
            'mimeType' => $result->getMimeType(),
        ];
    }

    /**
     * Resolve the endroid writer implementation for the given format.
     */
    private function writerFor(QrRenderFormat $format): WriterInterface
    {
        return match ($format) {
            QrRenderFormat::Png => new PngWriter,
            QrRenderFormat::Svg => new SvgWriter,
        };
    }
}
