"""Fictional Mail Send preparation; no API client, key, connection or email."""

import base64
import binascii
import hashlib
import io
import json
from importlib.metadata import version
from pathlib import Path

import reportlab
from pypdf import PdfReader
from pypdf.errors import PdfReadError
from reportlab.lib.colors import HexColor
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
from sendgrid.helpers.mail import Attachment, Disposition, FileContent, FileName, FileType, Mail


CHECKS = 0
MAIL_SERIALIZATIONS = 0
PDF_READER_ATTEMPTS = 0
PDF_READER_SUCCESSES = 0
PDF_READER_FAILURES = 0


def check(actual, expected):
    global CHECKS
    assert actual == expected, (actual, expected)
    CHECKS += 1


def fictional_pdf(reference, client_label, total_label):
    """Build one deterministic, visibly fictional PDF using original ReportLab."""
    font = Path(reportlab.__file__).parent / "fonts" / "Vera.ttf"
    if "FixtureVera" not in pdfmetrics.getRegisteredFontNames():
        pdfmetrics.registerFont(TTFont("FixtureVera", str(font)))
    stream = io.BytesIO()
    pdf = canvas.Canvas(stream, pagesize=A4, invariant=1, pageCompression=0)
    width, height = A4
    pdf.setTitle("Document fictif de recette Base64 - " + reference)
    pdf.setAuthor("Laboratoire de recette - aucune facture reelle")
    pdf.setFillColor(HexColor("#102c38"))
    pdf.rect(0, height - 150, width, 150, fill=1, stroke=0)
    pdf.setFillColor(HexColor("#ffffff"))
    pdf.setFont("FixtureVera", 18)
    pdf.drawString(42, height - 60, "FACTURE FICTIVE - TEST BASE64")
    pdf.setFont("FixtureVera", 11)
    pdf.drawString(42, height - 91, "Reference : " + reference)
    pdf.drawString(42, height - 114, "Aucun envoi email - aucune transaction")
    pdf.setFillColor(HexColor("#173847"))
    pdf.setFont("FixtureVera", 12)
    pdf.drawString(42, height - 195, client_label)
    pdf.setFont("FixtureVera", 10)
    pdf.drawString(42, height - 225, "Deux representations a distinguer : octets PDF et texte Base64.")
    pdf.setFillColor(HexColor("#edf4f5"))
    pdf.rect(42, height - 299, width - 84, 35, fill=1, stroke=0)
    pdf.setFillColor(HexColor("#173847"))
    pdf.drawString(54, height - 286, "Designation")
    pdf.drawRightString(430, height - 286, "Quantite")
    pdf.drawRightString(width - 54, height - 286, "Montant fictif")
    pdf.drawString(54, height - 329, "Document de demonstration")
    pdf.drawRightString(430, height - 329, "1")
    pdf.drawRightString(width - 54, height - 329, total_label)
    pdf.setStrokeColor(HexColor("#c9d9dd"))
    pdf.line(42, height - 350, width - 42, height - 350)
    pdf.setFont("FixtureVera", 12)
    pdf.drawString(42, height - 388, "Total de test")
    pdf.drawRightString(width - 42, height - 388, total_label)
    pdf.setFillColor(HexColor("#922f34"))
    pdf.setFont("FixtureVera", 11)
    pdf.drawString(42, 130, "DOCUMENT DE TEST - NE CONSTITUE PAS UNE FACTURE")
    pdf.setFillColor(HexColor("#536b75"))
    pdf.setFont("FixtureVera", 9)
    pdf.drawString(42, 104, "Noms, references et montants fictifs. Aucune donnee client.")
    pdf.drawString(42, 62, "Diagnostic technique Mail Send - page 1 / 1")
    pdf.save()
    return stream.getvalue()


def native_mail(content, filename="FICTIF-A-047.pdf", media_type="application/pdf",
                disposition="attachment", copies=1):
    global MAIL_SERIALIZATIONS
    mail = Mail(
        from_email="sender@example.invalid",
        to_emails="recipient@example.invalid",
        subject="Fictional attachment preparation - do not send",
        plain_text_content="Offline diagnostic with fictional documents.",
    )
    for _ in range(copies):
        mail.add_attachment(Attachment(
            file_content=FileContent(content),
            file_name=FileName(filename),
            file_type=FileType(media_type),
            disposition=Disposition(disposition),
        ))
    MAIL_SERIALIZATIONS += 1
    return mail.get()


def inspect_prepared_mail(payload, expected_pdf):
    """Check the actual SDK object; one strict Base64 decode, then native PDF read."""
    global PDF_READER_ATTEMPTS, PDF_READER_SUCCESSES, PDF_READER_FAILURES
    try:
        json.dumps(payload)
    except TypeError as error:
        return {"decision": "json_payload_review", "errorType": type(error).__name__}
    attachments = payload.get("attachments", [])
    if len(attachments) != 1:
        return {"decision": "attachment_count_review", "attachments": len(attachments)}
    attachment = attachments[0]
    if (attachment.get("filename") != "FICTIF-A-047.pdf"
            or attachment.get("type") != "application/pdf"
            or attachment.get("disposition") != "attachment"):
        return {"decision": "attachment_metadata_review"}
    content = attachment.get("content")
    if not isinstance(content, str):
        return {"decision": "content_type_review"}
    try:
        decoded = base64.b64decode(content, validate=True)
    except (binascii.Error, ValueError) as error:
        return {"decision": "base64_syntax_review", "errorType": type(error).__name__}
    prefix = decoded[:5].decode("ascii", errors="replace")
    PDF_READER_ATTEMPTS += 1
    try:
        reader = PdfReader(io.BytesIO(decoded), strict=True)
        text = "\n".join(page.extract_text() or "" for page in reader.pages)
        pages = len(reader.pages)
        PDF_READER_SUCCESSES += 1
    except PdfReadError as error:
        PDF_READER_FAILURES += 1
        return {"decision": "pdf_reader_review", "decodedOncePrefix": prefix,
                "pdfErrorType": type(error).__name__}
    actual_sha = hashlib.sha256(decoded).hexdigest()
    expected_sha = hashlib.sha256(expected_pdf).hexdigest()
    if actual_sha != expected_sha:
        return {"decision": "source_identity_review", "pages": pages,
                "decodedSha256": actual_sha, "expectedSha256": expected_sha}
    return {"decision": "prepared_fixture_matches", "pages": pages,
            "decodedSha256": actual_sha, "decodedOncePrefix": prefix,
            "fixtureReferenceFound": "FICTIF-A-047" in text}


def prepare_known_representation(value, representation, expected_pdf):
    if representation == "pdf_bytes" and isinstance(value, bytes):
        content = base64.b64encode(value).decode("ascii")
    elif representation == "base64_text" and isinstance(value, str):
        content = value
    else:
        return {"decision": "source_representation_review"}
    return inspect_prepared_mail(native_mail(content), expected_pdf)


def main():
    check(version("sendgrid"), "6.12.5")
    check(version("pypdf"), "6.21.0")
    check(version("reportlab"), "5.0.1")
    pdf_a = fictional_pdf("FICTIF-A-047", "CLIENT FICTIF A", "47,00 EUR")
    pdf_b = fictional_pdf("FICTIF-B-047", "CLIENT FICTIF B", "48,00 EUR")
    check(pdf_a.startswith(b"%PDF-"), True)
    check(pdf_a == pdf_b, False)
    encoded = base64.b64encode(pdf_a).decode("ascii")
    double_encoded = base64.b64encode(encoded.encode("ascii")).decode("ascii")
    naive_payload = native_mail(double_encoded)
    check(naive_payload["attachments"][0]["content"], double_encoded)
    naive = inspect_prepared_mail(naive_payload, pdf_a)
    check(naive["decision"], "pdf_reader_review")
    check(naive["decodedOncePrefix"], "JVBER")
    observations = [{"case": "double_encoded_pdf", **naive}]

    cases = [
        ("pass_through_base64", lambda: prepare_known_representation(
            encoded, "base64_text", pdf_a), "prepared_fixture_matches"),
        ("encode_raw_bytes_once", lambda: prepare_known_representation(
            pdf_a, "pdf_bytes", pdf_a), "prepared_fixture_matches"),
        ("different_readable_pdf", lambda: inspect_prepared_mail(native_mail(
            base64.b64encode(pdf_b).decode("ascii")), pdf_a), "source_identity_review"),
        ("raw_pdf_bytes_in_sdk", lambda: inspect_prepared_mail(
            native_mail(pdf_a), pdf_a), "json_payload_review"),
        ("invalid_base64", lambda: inspect_prepared_mail(
            native_mail("not!base64"), pdf_a), "base64_syntax_review"),
        ("data_uri_prefix", lambda: inspect_prepared_mail(native_mail(
            "data:application/pdf;base64," + encoded), pdf_a), "base64_syntax_review"),
        ("strict_profile_linebreak", lambda: inspect_prepared_mail(
            native_mail(encoded + "\n"), pdf_a), "base64_syntax_review"),
        ("html_named_pdf", lambda: inspect_prepared_mail(native_mail(
            base64.b64encode(b"<html>Fictional error page</html>").decode("ascii")), pdf_a),
            "pdf_reader_review"),
        ("truncated_pdf", lambda: inspect_prepared_mail(native_mail(
            base64.b64encode(pdf_a[:100]).decode("ascii")), pdf_a), "pdf_reader_review"),
        ("wrong_media_type", lambda: inspect_prepared_mail(
            native_mail(encoded, media_type="text/plain"), pdf_a), "attachment_metadata_review"),
        ("wrong_disposition", lambda: inspect_prepared_mail(
            native_mail(encoded, disposition="inline"), pdf_a), "attachment_metadata_review"),
        ("wrong_filename", lambda: inspect_prepared_mail(
            native_mail(encoded, filename="FICTIF-B-047.pdf"), pdf_a), "attachment_metadata_review"),
        ("two_attachments", lambda: inspect_prepared_mail(
            native_mail(encoded, copies=2), pdf_a), "attachment_count_review"),
        ("missing_attachment", lambda: inspect_prepared_mail(
            native_mail(encoded, copies=0), pdf_a), "attachment_count_review"),
        ("unknown_source_representation", lambda: prepare_known_representation(
            encoded, "auto", pdf_a), "source_representation_review"),
        ("wrong_declared_source_type", lambda: prepare_known_representation(
            encoded, "pdf_bytes", pdf_a), "source_representation_review"),
    ]
    for name, operation, decision in cases:
        result = operation()
        check(result["decision"], decision)
        if decision == "prepared_fixture_matches":
            check(result["pages"], 1)
            check(result["fixtureReferenceFound"], True)
            check(result["decodedSha256"], hashlib.sha256(pdf_a).hexdigest())
        observations.append({"case": name, **result})
    check(observations[1]["decodedSha256"], observations[2]["decodedSha256"])
    check(PDF_READER_ATTEMPTS, PDF_READER_SUCCESSES + PDF_READER_FAILURES)
    print(json.dumps({
        "sendgrid": version("sendgrid"), "pypdf": version("pypdf"),
        "reportlab": version("reportlab"), "checksPassed": CHECKS,
        "cases": len(observations), "nativeMailSerializations": MAIL_SERIALIZATIONS,
        "nativePdfReaderAttempts": PDF_READER_ATTEMPTS,
        "nativePdfReaderSuccesses": PDF_READER_SUCCESSES,
        "expectedNativePdfReaderFailures": PDF_READER_FAILURES,
        "pdfFixturesBuiltInMemory": 2, "pdfFilesWrittenByThisExecution": 0,
        "fixtureASha256": hashlib.sha256(pdf_a).hexdigest(),
        "fixtureBSha256": hashlib.sha256(pdf_b).hexdigest(),
        "naiveObservation": {"sdkPreservedSuppliedContent": True, **naive},
        "mailSendApiCalls": 0, "emailsSent": 0, "realCustomerData": False,
        "providerAcceptanceValidated": False, "observations": observations,
    }, indent=2))


if __name__ == "__main__":
    main()
