"""Synthetic MyDHL document-selection exercise. Never ships or prints anything."""
import argparse
import base64
import binascii
import hashlib
import io
import json
from pathlib import Path
import sys

import pypdf
from pypdf import PdfReader
from pypdf.errors import PdfReadError
import reportlab
from reportlab.lib.pagesizes import A4, A6
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen.canvas import Canvas

checks = []
connections = []
native_pdf_reads = 0
EXPECTED_SHIPMENT = "DEMO-SHIPMENT"


def deny_connection(event, args):
    if event == "socket.connect":
        connections.append(event)
        raise RuntimeError("The exercise cannot call DHL or a print server")


sys.addaudithook(deny_connection)


def check(name, condition):
    if name in checks or not condition:
        raise AssertionError(name)
    checks.append(name)


def make_pdf(markers, page_size):
    """Draw conspicuously fictitious documents with the real ReportLab library."""
    if "FixtureSans" not in pdfmetrics.getRegisteredFontNames():
        fonts = Path(reportlab.__file__).parent / "fonts"
        pdfmetrics.registerFont(TTFont("FixtureSans", str(fonts / "Vera.ttf")))
        pdfmetrics.registerFont(TTFont("FixtureSansBold", str(fonts / "VeraBd.ttf")))
    output = io.BytesIO()
    canvas = Canvas(output, pagesize=page_size, invariant=1, pageCompression=0)
    canvas.setTitle("Synthetic document-selection fixture - no postage")
    for marker in markers:
        if marker is None:
            canvas.showPage()
            continue
        height = page_size[1]
        canvas.setFont("FixtureSansBold", 16)
        canvas.drawString(24, height - 48, marker + " - FIXTURE")
        canvas.setFont("FixtureSans", 10)
        canvas.drawString(24, height - 80, "NOT VALID FOR POSTAGE")
        canvas.drawString(24, height - 100, "DEMO-SHIPMENT / P-01")
        canvas.drawString(24, height - 120, "No DHL barcode. No commercial use.")
        canvas.setFont("FixtureSans", 9)
        canvas.drawString(24, 28, "LOCAL TEST ONLY - DO NOT SHIP")
        canvas.showPage()
    canvas.save()
    return output.getvalue()


def read_pdf(raw):
    global native_pdf_reads
    native_pdf_reads += 1
    reader = PdfReader(io.BytesIO(raw), strict=True)
    if reader.is_encrypted:
        return {"encrypted": True}
    return {
        "encrypted": False,
        "pages": len(reader.pages),
        "firstLines": [((page.extract_text() or "").splitlines() or [""])[0] for page in reader.pages],
        "sha256": hashlib.sha256(raw).hexdigest(),
    }


def document(raw, role="label", image_format="PDF"):
    return {"imageFormat": image_format, "typeCode": role,
            "content": base64.b64encode(raw).decode("ascii")}


def response(documents):
    return {"shipmentTrackingNumber": EXPECTED_SHIPMENT, "documents": documents}


def select_for_review(data, request_profile, operation="create_shipment"):
    """Local single-document profile; returns a candidate, never a print command."""
    if operation != "create_shipment":
        return {"decision": "other_operation_review"}
    if data.get("shipmentTrackingNumber") != EXPECTED_SHIPMENT:
        return {"decision": "other_shipment_review"}
    if not isinstance(request_profile, dict) or type(request_profile.get("allDocumentsInOneImage")) is not bool:
        return {"decision": "missing_request_profile"}
    if request_profile["allDocumentsInOneImage"] or request_profile.get("receiptAndLabelsInOneImage"):
        return {"decision": "combined_document_profile_review"}
    documents = data.get("documents")
    if not isinstance(documents, list):
        return {"decision": "missing_document_collection"}
    labels = [item for item in documents if isinstance(item, dict) and item.get("typeCode") == "label"]
    if not labels:
        return {"decision": "missing_label_document"}
    if len(labels) != 1:
        return {"decision": "multiple_label_documents_review"}
    selected = labels[0]
    if "packageReferenceNumber" in selected:
        return {"decision": "piece_profile_review"}
    if "imageFormat" not in selected:
        return {"decision": "other_response_shape_review"}
    if selected["imageFormat"] != "PDF":
        return {"decision": "other_format_review"}
    if not isinstance(selected.get("content"), str):
        return {"decision": "other_content_type_review"}
    try:
        raw = base64.b64decode(selected["content"], validate=True)
    except (binascii.Error, ValueError):
        return {"decision": "invalid_base64"}
    if not raw.startswith(b"%PDF-"):
        return {"decision": "not_a_pdf"}
    try:
        parsed = read_pdf(raw)
    except (PdfReadError, ValueError):
        return {"decision": "native_pdf_read_error"}
    if parsed.get("encrypted") or parsed.get("pages", 0) == 0:
        return {"decision": "unavailable_pdf_pages"}
    return {"decision": "candidate_for_document_review", "declaredType": "label", "pdf": parsed}


def main(fixture_directory=None):
    invoice_pdf = make_pdf(["INVOICE"], A4)
    label_pdf = make_pdf(["LABEL"], A6)
    combined_pdf = make_pdf(["LABEL", "INVOICE"], A4)
    blank_pdf = make_pdf([None], A6)
    fixtures = {"invoice.pdf": invoice_pdf, "label.pdf": label_pdf, "combined.pdf": combined_pdf}
    for name, raw in fixtures.items():
        parsed = read_pdf(raw)
        check(name + "_native_read", parsed["pages"] == (2 if name == "combined.pdf" else 1))
        check(name + "_conspicuous_fixture", b"NOT VALID FOR POSTAGE" in raw)
    check("pypdf_pin", pypdf.__version__ == "6.0.0")
    check("reportlab_pin", reportlab.Version == "4.4.3")
    invoice = document(invoice_pdf, "invoice")
    label = document(label_pdf)
    profile = {"allDocumentsInOneImage": False, "receiptAndLabelsInOneImage": False}
    first = response([invoice, label])["documents"][0]
    naive_pdf = read_pdf(base64.b64decode(first["content"]))
    naive = {"claimedDestination": "label_queue", "declaredType": first["typeCode"],
             "pdfFirstLine": naive_pdf["firstLines"][0], "pdfReadable": naive_pdf["pages"] == 1}
    check("naive_really_reads_invoice", naive["declaredType"] == "invoice" and naive["pdfFirstLine"] == "INVOICE - FIXTURE")
    check("naive_pdf_is_readable", naive["pdfReadable"])
    wrong_field = dict(label)
    wrong_field["encodingFormat"] = wrong_field.pop("imageFormat")
    wrong_shipment = response([label])
    wrong_shipment["shipmentTrackingNumber"] = "OTHER-DEMO-SHIPMENT"
    cases = [
        ("invoice_before_label", response([invoice, label]), profile, "create_shipment", "candidate_for_document_review"),
        ("label_before_invoice", response([label, invoice]), profile, "create_shipment", "candidate_for_document_review"),
        ("combined_request", response([document(combined_pdf)]), {"allDocumentsInOneImage": True}, "create_shipment", "combined_document_profile_review"),
        ("receipt_combined_request", response([label]), {**profile, "receiptAndLabelsInOneImage": True}, "create_shipment", "combined_document_profile_review"),
        ("missing_profile", response([label]), None, "create_shipment", "missing_request_profile"),
        ("invoice_only", response([invoice]), profile, "create_shipment", "missing_label_document"),
        ("two_label_documents", response([label, label]), profile, "create_shipment", "multiple_label_documents_review"),
        ("piece_document", response([{**label, "packageReferenceNumber": 1}]), profile, "create_shipment", "piece_profile_review"),
        ("other_format", response([document(b"^XA^XZ", image_format="ZPL")]), profile, "create_shipment", "other_format_review"),
        ("other_operation", response([label]), profile, "get_image", "other_operation_review"),
        ("other_field_name", response([wrong_field]), profile, "create_shipment", "other_response_shape_review"),
        ("invalid_base64", response([{**label, "content": "%%%"}]), profile, "create_shipment", "invalid_base64"),
        ("unicode_base64", response([{**label, "content": "é"}]), profile, "create_shipment", "invalid_base64"),
        ("base64_non_pdf", response([document(b'{"test":true}')]), profile, "create_shipment", "not_a_pdf"),
        ("unreadable_pdf", response([document(b"%PDF-1.4\nnot a complete document\n%%EOF")]), profile, "create_shipment", "native_pdf_read_error"),
        ("missing_collection", {"shipmentTrackingNumber": EXPECTED_SHIPMENT}, profile, "create_shipment", "missing_document_collection"),
        ("other_shipment", wrong_shipment, profile, "create_shipment", "other_shipment_review"),
        ("metadata_lies_about_invoice", response([document(invoice_pdf)]), profile, "create_shipment", "candidate_for_document_review"),
        ("undeclared_combined_content", response([document(combined_pdf)]), profile, "create_shipment", "candidate_for_document_review"),
        ("readable_blank_pdf", response([document(blank_pdf)]), profile, "create_shipment", "candidate_for_document_review"),
    ]
    observations = []
    for name, data, options, operation, expected in cases:
        result = select_for_review(data, options, operation)
        check(name + "_decision", result["decision"] == expected)
        check(name + "_no_print_authorization", "printAuthorized" not in result)
        observations.append({"case": name, **result})
    by_name = {item["case"]: item for item in observations}
    check("order_change_same_label_bytes", by_name["invoice_before_label"]["pdf"]["sha256"] == by_name["label_before_invoice"]["pdf"]["sha256"] == hashlib.sha256(label_pdf).hexdigest())
    check("metadata_not_content_certificate", by_name["metadata_lies_about_invoice"]["pdf"]["firstLines"] == ["INVOICE - FIXTURE"])
    check("combined_content_not_detected_by_type_alone", by_name["undeclared_combined_content"]["pdf"]["firstLines"] == ["LABEL - FIXTURE", "INVOICE - FIXTURE"])
    check("readable_is_not_a_transport_label_certificate", by_name["readable_blank_pdf"]["pdf"]["firstLines"] == [""])
    check("no_network_connections", not connections)
    written = []
    if fixture_directory:
        destination = Path(fixture_directory)
        destination.mkdir(parents=True, exist_ok=True)
        for name, raw in fixtures.items():
            (destination/name).write_bytes(raw)
            written.append(name)
    print(json.dumps({"checksPassed": len(checks), "checks": checks,
                      "cases": len(cases), "nativePdfReads": native_pdf_reads,
                      "pypdf": pypdf.__version__, "reportlab": reportlab.Version,
                      "naiveObservation": naive, "observations": observations,
                      "localFixtureFilesWritten": written,
                      "networkConnectionAttempts": len(connections),
                      "dhlApiCalls": 0, "printerJobs": 0, "erpWrites": 0}, indent=2))


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--fixture-directory", help="Optionally save three clearly fictional local PDFs")
    main(parser.parse_args().fixture_directory)
