package de.oaa.libredeck.web.service.pdf;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

@Slf4j
@Component
public class QrCodeGenerator {

    // Logo covers 25% of QR width; well within the 30% H-level error-correction budget.
    static final float LOGO_RATIO = 0.25f;

    private final BufferedImage logoImage;

    public QrCodeGenerator() {
        BufferedImage logo = null;
        try (InputStream is = getClass().getResourceAsStream("/static/images/logo.png")) {
            if (is != null) logo = ImageIO.read(is);
        } catch (IOException e) {
            log.warn("Could not load logo for QR overlay: {}", e.getMessage());
        }
        logoImage = logo;
    }

    public BufferedImage generate(String content, int pixelSize) {
        try {
            BitMatrix matrix = new QRCodeWriter().encode(
                    content,
                    BarcodeFormat.QR_CODE,
                    pixelSize,
                    pixelSize,
                    Map.of(
                            EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H,
                            EncodeHintType.MARGIN, 1
                    )
            );
            BufferedImage qr = MatrixToImageWriter.toBufferedImage(matrix);
            return logoImage != null ? withLogo(qr) : qr;
        } catch (WriterException e) {
            throw new IllegalStateException("Failed to generate QR code for: " + content, e);
        }
    }

    /** Aspect ratio (height/width) of the logo, or 0 if no logo is loaded. */
    float logoAspect() {
        return logoImage == null ? 0f : (float) logoImage.getHeight() / logoImage.getWidth();
    }

	static int logoPillPad(int pixelSize) {
		return Math.max(3, pixelSize / 50);
	}

    private BufferedImage withLogo(BufferedImage qr) {
        int qrW   = qr.getWidth();
        int qrH   = qr.getHeight();
        int logoW = Math.round(qrW * LOGO_RATIO);
        int logoH = Math.round(logoW * (float) logoImage.getHeight() / logoImage.getWidth());
        int lx    = (qrW - logoW) / 2;
        int ly    = (qrH - logoH) / 2;

        BufferedImage result = new BufferedImage(qrW, qrH, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = result.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,  RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g.setRenderingHint(RenderingHints.KEY_RENDERING,      RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,   RenderingHints.VALUE_ANTIALIAS_ON);

        g.drawImage(qr, 0, 0, null);

        // White backing pill so the logo is readable regardless of QR modules beneath
        int pad = Math.max(3, qrW / 50);
        g.setColor(Color.WHITE);
        g.fillRoundRect(lx - pad, ly - pad, logoW + 2 * pad, logoH + 2 * pad, pad * 2, pad * 2);

        g.drawImage(logoImage, lx, ly, logoW, logoH, null);
        g.dispose();
        return result;
    }
}
