"""
qr_merge.py — Core library for inserting QR codes into a CarrierQR blank PDF.

Shared by the CLI (add_qr_codes.py) and the HTTP service (service.py).
"""

import io
from PIL import Image
import qrcode
from pypdf import PdfReader, PdfWriter

# Pixel coordinates of the two QR target rectangles in the 3541×2736 base image.
# Measured empirically from CarrierQR blank.pdf.
# (x_min, y_min, x_max, y_max)
LEFT_RECT  = (40,   200, 1233, 1401)   # Assembly/Submittal drawing
RIGHT_RECT = (2306, 200, 3501, 1401)   # Production drawing

# Inset so QR code does not touch the rectangle border.
PADDING_PX = 20


def generate_qr_image(url: str, size_px: int) -> Image.Image:
    """Return a square QR code PIL Image at size_px × size_px."""
    qr = qrcode.QRCode(
        error_correction=qrcode.constants.ERROR_CORRECT_M,
        box_size=10,
        border=1,
    )
    qr.add_data(url)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
    return img.resize((size_px, size_px), Image.LANCZOS)


def _composite_qr(base: Image.Image, url: str, rect: tuple) -> None:
    """Paste a centred QR code into rect on base (in-place)."""
    x1, y1, x2, y2 = rect
    avail_w = x2 - x1 - 2 * PADDING_PX
    avail_h = y2 - y1 - 2 * PADDING_PX
    qr_size = min(avail_w, avail_h)
    qr_img  = generate_qr_image(url, qr_size)
    paste_x = x1 + PADDING_PX + (avail_w - qr_size) // 2
    paste_y = y1 + PADDING_PX + (avail_h - qr_size) // 2
    base.paste(qr_img, (paste_x, paste_y))


def extract_base_image(pdf_bytes: bytes) -> Image.Image:
    """Extract the embedded JPEG from PDF bytes and return as PIL Image."""
    reader = PdfReader(io.BytesIO(pdf_bytes))
    page = reader.pages[0]
    for name, xobj in page["/Resources"]["/XObject"].items():
        if xobj.get("/Subtype") == "/Image":
            return Image.open(io.BytesIO(xobj._data)).convert("RGB")
    raise ValueError("No image XObject found in PDF")


def build_carrier_pdf(
    blank_pdf_bytes: bytes,
    submittal_url: str,
    production_url: str,
) -> bytes:
    """
    Main entry point. Given the blank carrier PDF bytes and two URLs,
    return the completed carrier PDF bytes with QR codes inserted.
    """
    base = extract_base_image(blank_pdf_bytes)
    _composite_qr(base, submittal_url, LEFT_RECT)
    _composite_qr(base, production_url, RIGHT_RECT)

    # Preserve the original page dimensions
    reader = PdfReader(io.BytesIO(blank_pdf_bytes))
    media_box = reader.pages[0].mediabox

    # Encode as JPEG then wrap in PDF
    img_buf = io.BytesIO()
    base.save(img_buf, format="JPEG", quality=95)
    img_buf.seek(0)

    pdf_buf = io.BytesIO()
    Image.open(img_buf).save(pdf_buf, format="PDF", resolution=72)
    pdf_buf.seek(0)

    tmp_reader = PdfReader(pdf_buf)
    writer = PdfWriter()
    writer.add_page(tmp_reader.pages[0])

    out = io.BytesIO()
    writer.write(out)
    return out.getvalue()
