
import sys
import win32print
import win32con
PRINTER_NAME_HINTS = ["4BARCODE 4B-2023PA"]  # edit to match your device name in Windows

# If you want to send a file instead, set ZPL_FILE and use send_file(...)
ZPL_FILE = None
# --------------------------

def find_printer_name(hints):
    """
    Return the first installed printer whose name contains any of the provided hints (case-insensitive).
    """
    flags = win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS
    printers = win32print.EnumPrinters(flags)
    # printers is a list of tuples; name is at index 2
    names = [p[2] for p in printers if len(p) > 2]
    # try hints
    for hint in hints:
        for name in names:
            if hint.lower() in name.lower():
                return name
    # fallback: if exactly one printer is installed, use it
    if len(names) == 1:
        return names[0]
    return None

def send_zpl_raw(printer_name: str, zpl: str, job_name: str = "ZPL RAW Job") -> None:
    """
    Send ZPL string as a RAW print job to the specified printer.
    """
    # Encode as cp1252 (or 'latin-1' / 'ascii') for ZPL; avoid BOM
    data = zpl.encode("cp1252", errors="replace")

    handle = win32print.OpenPrinter(printer_name)
    try:
        # Open a raw print job
        job_info = ("RAW", None, "RAW")
        hJob = win32print.StartDocPrinter(handle, 1, (job_name, None, "RAW"))
        try:
            win32print.StartPagePrinter(handle)
            win32print.WritePrinter(handle, data)
            win32print.EndPagePrinter(handle)
        finally:
            win32print.EndDocPrinter(handle)
    finally:
        win32print.ClosePrinter(handle)

def printLabel(dataToPrint):
    plu = dataToPrint['plu']
    name_en= dataToPrint['name_en']
    name_ch= dataToPrint['name_ch']
    lot_number = dataToPrint['lot_number']
    tare_weight = dataToPrint['tare_weight']
        
    best_before_date= dataToPrint['best_before_date']
    piece_count= dataToPrint['piece_count']
    weight_in_kg= dataToPrint['weight_in_kg']
    weight_in_lbs= dataToPrint['weight_in_lbs']
    barcode_str = dataToPrint['barcode_str']
    label_image_zpl = dataToPrint['label_image_zpl']
    is_sample = dataToPrint['is_sample']

    last_9 = barcode_str[-9:]
    sample = ""
    if (is_sample):
        sample = f"""
            ^CF0,70
            ^FO520,190^FDSAMPLE^FS
        """

    ZPL_TO_PRINT = f"""
        ^XA

        ^FWR
        ^CF0,60
        ^FO505,20^FD{plu}^FS

        {label_image_zpl}

        {sample}

        ^CF0,30
        ^FO340,20^FDLot/Batch #: {lot_number}^FS
        ^FO305,20^FDBest before date: {best_before_date}^FS
        ^FO275,20^FD# Pieces: {piece_count}^FS

        ^CF0,35
        ^FO325,470^FDNET WT:{weight_in_kg}KG^FS
        ^FO285,470^FDNET WT:{weight_in_lbs}LB^FS
        ^CF0,30
        ^FO245,470^FDTARE:{tare_weight}^FS

        ^FO115, 40 ^BY 2 ^BC , 110, , , , A ^FD {barcode_str} ^FS
        ^CF120,40
        ^FO030,200^FD{last_9}^FS

        ^CF0,20
        ^FO35,20^FDCreated by: QA Trace^FS

        ^CF0,35
        ^FO460,20^FD{name_en}^FS

        ^CW1,E:SIMSUN.TTF
        ^FWN
        ^A1R,40,40
        ^CI28
        ^CFJ,45
        ^FO400,20^FD{name_ch}^FS

        ^XZ
        """
    printer = find_printer_name(PRINTER_NAME_HINTS)
    if not printer:
        # Show installed printers to help you pick the exact name
        flags = win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS
        printers = win32print.EnumPrinters(flags)
        names = [p[2] for p in printers if len(p) > 2]
        print("Could not auto-detect a Zebra printer. Installed printers:\n  - " + "\n  - ".join(names))
        print("\nSet PRINTER_NAME_HINTS to match your printer name exactly.")
        sys.exit(1)

    print(f"Using printer: {printer}")
    send_zpl_raw(printer, ZPL_TO_PRINT)

    print("ZPL sent successfully.")


if __name__ == "__main__":
    printLabel()

