"""Copie signée d'un formulaire PADI : signature, date et nom superposés sur le PDF officiel.

Le PDF d'origine n'est jamais modifié ni recopié : on lui ajoute une couche par-dessus, à l'endroit des
lignes de signature. Les coordonnées sont en points PDF, origine en haut à gauche de la page (la
conversion vers le repère du PDF se fait ici), mesurées sur les fichiers de Doc/OW.
"""
import io
from datetime import date

from PIL import Image
from pypdf import PdfReader, PdfWriter
from reportlab.lib.utils import ImageReader
from reportlab.pdfgen import canvas

SIG, DATE, NAME = 'sig', 'date', 'name'
FONT, FONT_SIZE = 'Helvetica', 10

# code du formulaire → {'pages': pages gardées (None = toutes), 'items': [(rôle, nature, page, géométrie)]}
# Géométrie : (x0, y0, x1, y1) pour une signature, (x, y) pour un texte (y = ligne de base).
PLACEMENTS = {
    '10060F': {'pages': None, 'items': [
        ('student', NAME, 0, (120, 222)),
        ('student', SIG, 0, (95, 668, 385, 697)), ('student', DATE, 0, (410, 695)),
        ('guardian', SIG, 0, (95, 707, 385, 736)), ('guardian', DATE, 0, (410, 734)),
    ]},
    '10062F': {'pages': None, 'items': [
        ('student', NAME, 0, (78, 180)),
        ('student', SIG, 0, (60, 690, 310, 719)), ('student', DATE, 0, (372, 717)),
        ('guardian', SIG, 0, (60, 729, 310, 758)), ('guardian', DATE, 0, (372, 756)),
    ]},
    '10072F': {'pages': None, 'items': [
        ('student', SIG, 0, (50, 704, 200, 730)), ('student', DATE, 0, (450, 712)),
        ('guardian', SIG, 0, (50, 733, 165, 756)), ('guardian', DATE, 0, (450, 742)),
    ]},
    '10615F': {'pages': None, 'items': [
        ('guardian', NAME, 0, (45, 683)),
        ('guardian', SIG, 0, (275, 650, 495, 681)), ('guardian', DATE, 0, (507, 683)),
        ('minor', NAME, 0, (45, 715)),
        ('minor', SIG, 0, (275, 696, 495, 713)), ('minor', DATE, 0, (507, 715)),
    ]},
    # Pages 1 à 3 seulement : les pages 4 à 6 du PDF sont le corrigé de l'instructeur.
    '381DT': {'pages': (0, 1, 2), 'items': [
        ('student', NAME, 0, (270, 49)), ('student', DATE, 0, (498, 49)),
        ('student', SIG, 2, (112, 509, 305, 527)), ('student', DATE, 2, (95, 548)),
    ]},
}


def can_stamp(code):
    return code in PLACEMENTS


def _fit(png):
    """Signature rognée à son tracé, pour qu'elle remplisse la zone au lieu de flotter dans la marge."""
    img = Image.open(io.BytesIO(png)).convert('RGBA')
    box = img.getchannel('A').getbbox()
    return img.crop(box) if box else img


def stamp(src_path, code, signatures):
    """PDF signé en octets.

    signatures : {rôle: {'image': PNG en octets, 'date': date, 'name': str}} ; seuls les rôles présents sont posés.
    """
    plan = PLACEMENTS[code]
    reader = PdfReader(src_path)
    keep = plan['pages'] if plan['pages'] is not None else range(len(reader.pages))
    writer = PdfWriter()
    for index in keep:
        page = reader.pages[index]
        width, height = float(page.mediabox.width), float(page.mediabox.height)
        buffer = io.BytesIO()
        pdf = canvas.Canvas(buffer, pagesize=(width, height))
        pdf.setFont(FONT, FONT_SIZE)
        for role, kind, page_no, geom in plan['items']:
            data = signatures.get(role)
            if page_no != index or not data:
                continue
            if kind == SIG:
                x0, y0, x1, y1 = geom
                img = _fit(data['image'])
                scale = min((x1 - x0) / img.width, (y1 - y0) / img.height)
                w, h = img.width * scale, img.height * scale
                pdf.drawImage(ImageReader(img), x0, height - y1 + ((y1 - y0) - h) / 2, w, h, mask='auto')
            else:
                text = data['name'] if kind == NAME else data['date'].strftime('%d/%m/%Y')
                x, y = geom
                pdf.drawString(x, height - y, text)
        pdf.save()
        buffer.seek(0)
        # La page doit appartenir au document avant d'y superposer la couche (exigé par pypdf 7)
        writer.add_page(page).merge_page(PdfReader(buffer).pages[0])
    out = io.BytesIO()
    writer.add_metadata({'/Title': f'Formulaire PADI {code} signé', '/Producer': 'formation.goscubatours.com'})
    writer.write(out)
    return out.getvalue()
