from pathlib import Path
from collections import deque
from PIL import Image
from reportlab.lib.colors import HexColor, black, white
from reportlab.lib.pagesizes import A3, landscape
from reportlab.graphics.barcode import qr
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
from reportlab.graphics.shapes import Drawing
from reportlab.graphics import renderPDF

ROOT = Path('/home/sebas/work/tasks/T-bbx-print-20260520')
SRC_LOGO = Path('/home/sebas/work/projects/ballbox/public/images/ballbox-logo.png')
URL = 'https://ballbox.app'
BRAND = HexColor('#B7D334')
DARK = HexColor('#111111')


def build_mask(img):
    w, h = img.size
    px = img.load()
    mask = [[0]*w for _ in range(h)]
    for y in range(h):
        for x in range(w):
            r, g, b, a = px[x, y]
            bright = max(r, g, b)
            greenish = g > 70 and g >= r * 0.8 and g >= b * 0.8
            if bright > 85 or greenish:
                mask[y][x] = 1
    # keep only large connected components
    seen = [[False]*w for _ in range(h)]
    comps = []
    for y in range(h):
        for x in range(w):
            if mask[y][x] and not seen[y][x]:
                q = deque([(x,y)])
                seen[y][x] = True
                pts = []
                while q:
                    cx, cy = q.popleft()
                    pts.append((cx,cy))
                    for nx, ny in ((cx+1,cy),(cx-1,cy),(cx,cy+1),(cx,cy-1)):
                        if 0 <= nx < w and 0 <= ny < h and mask[ny][nx] and not seen[ny][nx]:
                            seen[ny][nx] = True
                            q.append((nx,ny))
                comps.append(pts)
    comps.sort(key=len, reverse=True)
    out = [[0]*w for _ in range(h)]
    for pts in comps[:16]:
        if len(pts) < 20:
            continue
        for x, y in pts:
            out[y][x] = 1
    return out


def dilate(mask, radius=1):
    h = len(mask); w = len(mask[0])
    out = [[0]*w for _ in range(h)]
    for y in range(h):
        for x in range(w):
            if mask[y][x]:
                for dy in range(-radius, radius+1):
                    for dx in range(-radius, radius+1):
                        nx, ny = x+dx, y+dy
                        if 0 <= nx < w and 0 <= ny < h:
                            out[ny][nx] = 1
    return out


def crop_bbox(mask):
    ys = [y for y,row in enumerate(mask) if any(row)]
    xs = [x for x in range(len(mask[0])) if any(mask[y][x] for y in range(len(mask)))]
    return min(xs), min(ys), max(xs)+1, max(ys)+1


def render_logo(variant):
    img = Image.open(SRC_LOGO).convert('RGBA')
    mask = dilate(build_mask(img), 1)
    x0,y0,x1,y1 = crop_bbox(mask)
    w, h = x1-x0, y1-y0
    out = Image.new('RGBA', (w, h), (0,0,0,0))
    src = img.load()
    dst = out.load()
    for y in range(h):
        for x in range(w):
            if mask[y+y0][x+x0]:
                r,g,b,a = src[x+x0,y+y0]
                if variant == 'green':
                    # normalize dark anti-alias to brand green
                    dst[x,y] = (183, 211, 52, 255)
                elif variant == 'black':
                    dst[x,y] = (17,17,17,255)
    target_w = 2400
    target_h = int(out.height * (target_w / out.width))
    out = out.resize((target_w, target_h), Image.LANCZOS)
    path = ROOT / f'ballbox-logo-{variant}-clean.png'
    out.save(path)
    return path


def make_pdf(logo_path, out_pdf, heading=None):
    page_w, page_h = landscape(A3)
    c = canvas.Canvas(str(out_pdf), pagesize=(page_w, page_h))
    margin = 42
    safe_x = margin
    safe_y = margin
    safe_w = page_w - margin * 2
    safe_h = page_h - margin * 2
    c.setFillColor(white)
    c.rect(0, 0, page_w, page_h, stroke=0, fill=1)
    c.setStrokeColor(BRAND)
    c.setLineWidth(2)
    c.roundRect(safe_x, safe_y, safe_w, safe_h, 18, stroke=1, fill=0)
    logo = ImageReader(str(logo_path))
    iw, ih = Image.open(logo_path).size
    logo_max_w = safe_w * 0.50
    logo_max_h = safe_h * 0.60
    scale = min(logo_max_w / iw, logo_max_h / ih)
    draw_w = iw * scale
    draw_h = ih * scale
    logo_x = safe_x + 48
    logo_y = (page_h - draw_h) / 2 + 24
    c.drawImage(logo, logo_x, logo_y, width=draw_w, height=draw_h, mask='auto')
    qr_size = safe_h * 0.48
    qr_x = safe_x + safe_w - qr_size - 70
    qr_y = (page_h - qr_size) / 2 + 38
    widget = qr.QrCodeWidget(URL)
    bounds = widget.getBounds()
    bw = bounds[2] - bounds[0]
    bh = bounds[3] - bounds[1]
    d = qr_size
    drawing = Drawing(d, d, transform=[d / bw, 0, 0, d / bh, 0, 0])
    drawing.add(widget)
    pad = 18
    c.setFillColor(white)
    c.setStrokeColor(DARK)
    c.setLineWidth(1.2)
    c.roundRect(qr_x - pad, qr_y - pad, qr_size + 2*pad, qr_size + 2*pad, 14, stroke=1, fill=1)
    renderPDF.draw(drawing, c, qr_x, qr_y)
    line_y = page_h / 2
    c.setStrokeColor(BRAND)
    c.setLineWidth(4)
    c.line(logo_x + draw_w + 24, line_y, qr_x - 36, line_y)
    c.setFillColor(DARK)
    c.setFont('Helvetica-Bold', 28)
    c.drawCentredString(qr_x + qr_size / 2, qr_y - 46, 'Escaneá y entrá')
    c.setFont('Helvetica', 18)
    c.drawCentredString(qr_x + qr_size / 2, qr_y - 72, URL)
    if heading:
        c.setFont('Helvetica', 12)
        c.drawString(safe_x + 18, page_h - safe_y - 22, heading)
    c.showPage()
    c.save()


def main():
    green = render_logo('green')
    blackv = render_logo('black')
    make_pdf(green, ROOT / 'ballbox-plot-a3-horizontal-clean-green.pdf')
    make_pdf(blackv, ROOT / 'ballbox-plot-a3-horizontal-black.pdf')
    print('done')

if __name__ == '__main__':
    main()
