"""
Formal PDF certificate generation (ReportLab).
Looks authoritative: border, seal, signature line, QR → public verify URL.
"""
from __future__ import annotations

import io
from pathlib import Path

from django.conf import settings


def _site_branding():
    from apps.dashboard.models import SiteSettings
    return SiteSettings.load()


def _verify_absolute_url(cert) -> str:
    site = _site_branding()
    configured = (site.certificate_verify_url or '').strip().rstrip('/')
    base = getattr(settings, 'PUBLIC_SITE_URL', '').rstrip('/')
    path = cert.get_verify_path()
    if configured and '{id}' in configured:
        return configured.replace('{id}', cert.certificate_number)
    if configured and configured.endswith('/verify'):
        return f'{configured}/{cert.certificate_number}'
    if base:
        return f'{base}{path}'
    # Relative printed as absolute-looking path for QR; verify page still works on same host
    return path


def _qr_image(url: str, box_size: int = 6):
    import qrcode
    from reportlab.lib.utils import ImageReader

    qr = qrcode.QRCode(version=1, box_size=box_size, border=1)
    qr.add_data(url)
    qr.make(fit=True)
    img = qr.make_image(fill_color='#0f172a', back_color='white')
    buf = io.BytesIO()
    img.save(buf, format='PNG')
    buf.seek(0)
    return ImageReader(buf)


def _optional_image(path_or_field):
    from reportlab.lib.utils import ImageReader

    if not path_or_field:
        return None
    try:
        if hasattr(path_or_field, 'path'):
            p = path_or_field.path
        else:
            p = str(path_or_field)
        if p and Path(p).is_file():
            return ImageReader(p)
    except Exception:
        return None
    # Fall back to static seal / signature samples
    return None


def _static_image(name: str):
    from reportlab.lib.utils import ImageReader

    candidates = [
        Path(settings.BASE_DIR) / 'static' / 'images' / 'certificates' / name,
        Path(settings.BASE_DIR) / 'static' / 'images' / name,
    ]
    for p in candidates:
        if p.is_file():
            return ImageReader(str(p))
    return None


def build_certificate_pdf_bytes(cert) -> bytes:
    """Return PDF bytes for a CourseCertificate."""
    from reportlab.lib.colors import Color, HexColor, white
    from reportlab.lib.pagesizes import A4, landscape
    from reportlab.lib.units import mm
    from reportlab.pdfgen import canvas

    site = _site_branding()
    institute = site.institute_name or 'TSN Digital Academy'
    signer = (site.certificate_signer_name or '').strip() or 'Director'
    signer_title = (site.certificate_signer_title or '').strip() or 'Director'
    verify_url = _verify_absolute_url(cert)

    page = landscape(A4)
    width, height = page
    buf = io.BytesIO()
    c = canvas.Canvas(buf, pagesize=page)

    navy = HexColor('#0f2557')
    gold = HexColor('#b45309')
    ink = HexColor('#0f172a')
    muted = HexColor('#475569')

    # Outer double border
    margin = 12 * mm
    c.setStrokeColor(navy)
    c.setLineWidth(3)
    c.rect(margin, margin, width - 2 * margin, height - 2 * margin)
    c.setStrokeColor(gold)
    c.setLineWidth(1.2)
    inset = margin + 4 * mm
    c.rect(inset, inset, width - 2 * inset, height - 2 * inset)

    # Corner ornaments
    c.setStrokeColor(gold)
    c.setLineWidth(1)
    orn = 10 * mm
    for x0, y0, dx, dy in (
        (inset, inset, 1, 1),
        (width - inset, inset, -1, 1),
        (inset, height - inset, 1, -1),
        (width - inset, height - inset, -1, -1),
    ):
        c.line(x0, y0, x0 + dx * orn, y0)
        c.line(x0, y0, x0, y0 + dy * orn)

    # Header
    c.setFillColor(navy)
    c.setFont('Times-Bold', 22)
    c.drawCentredString(width / 2, height - 32 * mm, institute.upper())
    c.setFont('Times-Roman', 11)
    c.setFillColor(gold)
    c.drawCentredString(width / 2, height - 40 * mm, 'CERTIFICATE OF ACHIEVEMENT')

    c.setStrokeColor(gold)
    c.setLineWidth(0.8)
    c.line(width / 2 - 55 * mm, height - 44 * mm, width / 2 + 55 * mm, height - 44 * mm)

    c.setFillColor(muted)
    c.setFont('Times-Italic', 12)
    c.drawCentredString(width / 2, height - 54 * mm, 'This is to certify that')

    c.setFillColor(ink)
    c.setFont('Times-BoldItalic', 26)
    c.drawCentredString(width / 2, height - 68 * mm, cert.recipient_name)

    c.setFillColor(muted)
    c.setFont('Times-Roman', 12)
    c.drawCentredString(
        width / 2,
        height - 80 * mm,
        'has successfully completed the examination for',
    )

    c.setFillColor(navy)
    c.setFont('Times-Bold', 16)
    title = cert.course_title_snapshot or cert.course.title
    c.drawCentredString(width / 2, height - 92 * mm, title)

    c.setFillColor(ink)
    c.setFont('Times-Roman', 12)
    band = cert.score_band_label
    issued = cert.issued_at.strftime('%d %B %Y') if cert.issued_at else ''
    assessment = getattr(cert, 'assessment_label', None) or 'Knowledge Assessment'
    c.drawCentredString(
        width / 2,
        height - 104 * mm,
        f'{band}  ·  Issued {issued}',
    )
    c.setFillColor(gold)
    c.setFont('Times-Bold', 11)
    c.drawCentredString(width / 2, height - 112 * mm, assessment)

    # Seal (right of center-bottom)
    seal = _optional_image(site.certificate_seal) or _static_image('golden_seal.png')
    if seal:
        seal_w = 32 * mm
        c.drawImage(
            seal,
            width / 2 - seal_w / 2,
            38 * mm,
            width=seal_w,
            height=seal_w,
            mask='auto',
            preserveAspectRatio=True,
        )

    # Signature block (left)
    sig = _optional_image(site.certificate_signature) or _static_image('director_signature.png')
    sig_x = 40 * mm
    sig_y = 42 * mm
    if sig:
        c.drawImage(sig, sig_x, sig_y + 8 * mm, width=45 * mm, height=16 * mm, mask='auto', preserveAspectRatio=True)
    c.setStrokeColor(ink)
    c.setLineWidth(0.6)
    c.line(sig_x, sig_y + 6 * mm, sig_x + 50 * mm, sig_y + 6 * mm)
    c.setFont('Times-Bold', 11)
    c.setFillColor(ink)
    c.drawString(sig_x, sig_y, signer)
    c.setFont('Times-Roman', 9)
    c.setFillColor(muted)
    c.drawString(sig_x, sig_y - 5 * mm, signer_title)
    c.setFont('Times-Italic', 8)
    c.drawString(sig_x, sig_y - 10 * mm, 'Digitally signed · integrity verified')

    # QR + ID (right)
    qr = _qr_image(verify_url, box_size=5)
    qr_size = 28 * mm
    qr_x = width - 55 * mm
    qr_y = 40 * mm
    c.drawImage(qr, qr_x, qr_y, width=qr_size, height=qr_size, mask='auto')
    c.setFont('Helvetica', 7)
    c.setFillColor(muted)
    c.drawCentredString(qr_x + qr_size / 2, qr_y - 5 * mm, 'Scan to verify')
    c.setFont('Helvetica-Bold', 8)
    c.setFillColor(navy)
    c.drawRightString(width - 22 * mm, 28 * mm, f'ID: {cert.certificate_number}')
    c.setFont('Helvetica', 7)
    c.setFillColor(muted)
    c.drawRightString(width - 22 * mm, 23 * mm, verify_url[:70])

    # Hash footer (truncated)
    if cert.integrity_hash:
        c.setFont('Helvetica', 6)
        c.setFillColor(Color(0.4, 0.45, 0.5))
        c.drawCentredString(
            width / 2,
            16 * mm,
            f'Digital seal: {cert.integrity_hash[:32]}…',
        )

    c.showPage()
    c.save()
    return buf.getvalue()
