"""
Printer font & symbol test script.
Usage (inside Docker):  python print_test.py [IP] [PORT]
Defaults to 10.98.20.25:9100
"""
import sys

PRINTER_IP   = sys.argv[1] if len(sys.argv) > 1 else "10.98.20.25"
PRINTER_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 9100

from escpos.printer import Network

def _gr(text: str) -> bytes:
    return text.encode('cp737', errors='replace')

def _open():
    p = Network(PRINTER_IP, PRINTER_PORT, timeout=10)
    p._raw(b'\x1b\x40')       # ESC @ reset
    p._raw(b'\x1b\x74\x1d')   # CP737 Greek code page
    return p

def _t(p, text: str):
    p._raw(_gr(text))

def _divider(p, char="-", width=48):
    p._raw(b'\x1b\x61\x00')
    _t(p, char * width + "\n")

def _center(p):
    p._raw(b'\x1b\x61\x01')

def _left(p):
    p._raw(b'\x1b\x61\x00')

# ── ESC ! n byte reference ──────────────────────────────────────────────────
# Bit 0 → underline (not tested, minor)
# Bit 1 → double-strike (bold)
# Bit 3 → double-height
# Bit 4 → double-width
# Bit 5 → delete-line
# Bit 7 → bold (ESC E alias in some models)
# Common combos used here:
#   0x00 = normal
#   0x08 = double-height only           (48 chars wide)
#   0x10 = double-height only (alt bit) (48 chars wide)
#   0x18 = double-height + bold
#   0x20 = double-width only            (24 chars wide)
#   0x30 = double-width + double-height (24 chars wide)
#   0x38 = double-width + double-height + bold
#   0x48 = double-height (bit 6 combo — some printers)

MODES = [
    (0x00, "Normal (0x00)"),
    (0x08, "Double-height bit3 (0x08)"),
    (0x10, "Double-height bit4 (0x10)"),
    (0x18, "Double-height + Bold (0x18)"),
    (0x20, "Double-width (0x20)"),
    (0x30, "Double-width + Double-height (0x30)"),
    (0x38, "Double-width + Double-height + Bold (0x38)"),
]

# ── Section 1 — Font sizes & styles, English ───────────────────────────────

def section_english(p):
    _center(p)
    p._raw(b'\x1b\x21\x38')
    _t(p, "=== FONT SIZES (EN) ===\n")
    p._raw(b'\x1b\x21\x00')
    _divider(p, "=")

    for code, label in MODES:
        _left(p)
        _t(p, f"[{label}]\n")
        p._raw(bytes([0x1b, 0x21, code]))
        _t(p, "TEST PRINT  Hello World  Abc123\n")
        p._raw(b'\x1b\x21\x00')
        # bold on/off via ESC E
        _t(p, "  -> bold ON:  ")
        p._raw(b'\x1b\x45\x01')
        p._raw(bytes([0x1b, 0x21, code]))
        _t(p, "Bold Sample\n")
        p._raw(b'\x1b\x45\x00')
        p._raw(b'\x1b\x21\x00')
        _t(p, "\n")

    _divider(p)
    p._raw(b'\n')

# ── Section 2 — Font sizes & styles, Greek ─────────────────────────────────

def section_greek(p):
    _center(p)
    p._raw(b'\x1b\x21\x38')
    _t(p, "=== FONT SIZES (GR) ===\n")
    p._raw(b'\x1b\x21\x00')
    _divider(p, "=")

    for code, label in MODES:
        _left(p)
        _t(p, f"[{label}]\n")
        p._raw(bytes([0x1b, 0x21, code]))
        _t(p, "ΔΟΚΙΜΑΣΤΙΚΗ ΕΚΤΥΠΩΣΗ\n")
        _t(p, "δοκιμαστικη εκτυπωση\n")   # lowercase
        p._raw(b'\x1b\x21\x00')
        p._raw(b'\x1b\x45\x01')
        p._raw(bytes([0x1b, 0x21, code]))
        _t(p, "Bold: Καλημερα Κοσμε\n")
        p._raw(b'\x1b\x45\x00')
        p._raw(b'\x1b\x21\x00')
        _t(p, "\n")

    _divider(p)
    p._raw(b'\n')

# ── Section 3 — All printable ASCII symbols ────────────────────────────────

def section_ascii_symbols(p):
    _center(p)
    p._raw(b'\x1b\x21\x18')   # double-height bold for header
    _t(p, "=== ASCII SYMBOLS ===\n")
    p._raw(b'\x1b\x21\x00')
    _divider(p, "=")
    _left(p)

    # Printable ASCII 0x20 – 0x7E, 16 per line
    chars = [chr(c) for c in range(0x20, 0x7F)]
    line = ""
    for i, ch in enumerate(chars):
        line += ch + " "
        if (i + 1) % 24 == 0:
            _t(p, line + "\n")
            line = ""
    if line:
        _t(p, line + "\n")

    _t(p, "\n")
    _t(p, "Notable:\n")
    _t(p, "  Bullets  :  * + - # @ ! ? > < | / \\ ^ ~ _\n")
    _t(p, "  Framing  :  [ ] { } ( ) = : ; , . \"\n")
    _t(p, "  Currency :  $ %\n")
    _divider(p)
    p._raw(b'\n')

# ── Section 4 — CP737 extended chars (0x80–0xFF) ───────────────────────────

def section_extended(p):
    _center(p)
    p._raw(b'\x1b\x21\x18')
    _t(p, "=== CP737 EXTENDED (0x80-FF) ===\n")
    p._raw(b'\x1b\x21\x00')
    _divider(p, "=")
    _left(p)
    _t(p, "Hex offset rows x16 columns\n\n")

    for row in range(8):            # 0x80, 0x90 ... 0xF0
        base = 0x80 + row * 16
        row_bytes = bytes(range(base, base + 16))
        label = f"0x{base:02X}: "
        p._raw(_gr(label))
        p._raw(row_bytes)
        p._raw(b'\n')

    _t(p, "\n")
    _t(p, "Key CP737 specials:\n")
    specials = [
        (0xB3, "─ thin horiz line"),
        (0xC4, "─ double line"),
        (0xBA, "│ vert line"),
        (0xBB, "┐ corner"),
        (0xBC, "┘ corner"),
        (0xC9, "╔ corner"),
        (0xCA, "╩ junction"),
        (0xCB, "╦ junction"),
        (0xCC, "╠ junction"),
        (0xCD, "═ double horiz"),
        (0xCE, "╬ cross"),
        (0xC8, "╚ corner"),
        (0xBB, "╗ corner"),
        (0xBC, "╝ corner"),
        (0xDB, "█ full block"),
        (0xDC, "▄ lower block"),
        (0xDF, "▀ upper block"),
        (0xB0, "░ light shade"),
        (0xB1, "▒ medium shade"),
        (0xB2, "▓ dark shade"),
        (0xF8, "° degree"),
        (0xF9, "· middle dot"),
        (0xFA, "· bullet dot"),
        (0xFB, "√ check / tick"),
        (0xFE, "■ filled square"),
    ]
    for code, desc in specials:
        row_bytes = bytes([code, 0x20])  # char + space
        p._raw(row_bytes)
        _t(p, f" {desc}\n")

    _divider(p)
    p._raw(b'\n')

# ── Section 5 — Underline ──────────────────────────────────────────────────

def section_underline(p):
    _center(p)
    p._raw(b'\x1b\x21\x18')
    _t(p, "=== UNDERLINE TEST ===\n")
    p._raw(b'\x1b\x21\x00')
    _divider(p, "=")
    _left(p)

    # ESC - n : underline  0=off, 1=thin, 2=thick
    for ul in [1, 2]:
        p._raw(bytes([0x1b, 0x2d, ul]))
        _t(p, f"Underline mode {ul}: TEST PRINT Abc123\n")
        p._raw(b'\x1b\x2d\x00')   # off
    _t(p, "\n")
    _divider(p)
    p._raw(b'\n')

# ── Section 6 — Inverted / white-on-black ─────────────────────────────────

def section_invert(p):
    _center(p)
    p._raw(b'\x1b\x21\x18')
    _t(p, "=== INVERT (white-on-black) ===\n")
    p._raw(b'\x1b\x21\x00')
    _divider(p, "=")
    _left(p)

    # GS B n  — invert
    p._raw(b'\x1d\x42\x01')
    _t(p, " INVERTED TEXT SAMPLE \n")
    p._raw(b'\x1d\x42\x00')
    _t(p, "Normal text after invert\n")
    _t(p, "\n")
    _divider(p)
    p._raw(b'\n')

# ── Section 7 — QR Code sample ────────────────────────────────────────────

def section_qr(p):
    _center(p)
    p._raw(b'\x1b\x21\x18')
    _t(p, "=== QR CODE SAMPLE ===\n")
    p._raw(b'\x1b\x21\x00')
    _divider(p, "=")

    data = b"https://pos.test"
    # GS ( k — QR store data
    store_len = len(data) + 3
    p._raw(b'\x1d\x28\x6b' + bytes([store_len & 0xFF, (store_len >> 8) & 0xFF, 0x31, 0x50, 0x30]) + data)
    # GS ( k — set size (module=6)
    p._raw(b'\x1d\x28\x6b\x03\x00\x31\x43\x06')
    # GS ( k — error correction level M
    p._raw(b'\x1d\x28\x6b\x03\x00\x31\x45\x31')
    # GS ( k — print
    p._raw(b'\x1d\x28\x6b\x03\x00\x31\x51\x30')

    _t(p, "\nhttps://pos.test\n\n")
    _divider(p)
    p._raw(b'\n')

# ── Main ───────────────────────────────────────────────────────────────────

def main():
    print(f"Connecting to {PRINTER_IP}:{PRINTER_PORT} ...")

    # ---- PAGE 1: English fonts ----
    p = _open()
    section_english(p)
    p._raw(b'\n\n\n')
    p.cut()
    p.close()
    print("Page 1 sent (English fonts)")

    # ---- PAGE 2: Greek fonts ----
    p = _open()
    section_greek(p)
    p._raw(b'\n\n\n')
    p.cut()
    p.close()
    print("Page 2 sent (Greek fonts)")

    # ---- PAGE 3: Symbols & special chars ----
    p = _open()
    section_ascii_symbols(p)
    section_extended(p)
    p._raw(b'\n\n\n')
    p.cut()
    p.close()
    print("Page 3 sent (ASCII + CP737 extended)")

    # ---- PAGE 4: Underline + Invert + QR ----
    p = _open()
    section_underline(p)
    section_invert(p)
    section_qr(p)
    p._raw(b'\n\n\n')
    p.cut()
    p.close()
    print("Page 4 sent (underline / invert / QR)")

    print("Done — 4 pages printed.")

if __name__ == "__main__":
    main()
