from .logo_to_sbpl import image_to_sbpl
import json
import win32print
from datetime import datetime
import os

ESC = b"\x1b"
DPI = 305
DOTS_PER_MM = DPI / 25.4  # ~12.0

# ======= AJUSTES =======
PRINTER = "SATO_RAW"

LABEL_W_MM = 40.0
GAP_MM     = 4.0
SIDE       = "right"

SPEED_IPS  = 4
DARKNESS   = 10

SHIFT_X_MM = 16.0
SHIFT_Y_MM = 0.6

# Fonte
TEXT_FONT = b"XS"
FONT_P    = 1
FONT_L    = b"0200"

# QR
QR_MODULE = 4
QR_X_MM   = 25.0
QR_Y_MM   = 2.0
# =======================

# ======= METADADOS POR MODELO =======
# Versão do firmware e alimentação impressas na etiqueta. Os modelos STM32/PIMA
# usam o padrão (1.2 / 100-240 V); o modelo GSM tem valores próprios.
DEFAULT_LABEL_INFO = {"version": "1.2", "power": "100-240 V"}
MODEL_LABEL_INFO = {
    "SI-EMA Q": {"version": "1.0", "power": "5V 2A"},
}

def label_info_for(model: str) -> dict:
    return MODEL_LABEL_INFO.get((model or "").strip().upper(), DEFAULT_LABEL_INFO)
# =====================================

    
def get_print_dir():
    return os.path.dirname(os.path.abspath(__file__))

def mm_to_dots4(mm: float) -> bytes:
    d = int(round(mm * DOTS_PER_MM))
    d = max(0, min(9999, d))
    return f"{d:04d}".encode("ascii")

def H(mm_x: float, base_x_mm: float) -> bytes:
    return ESC + b"H" + mm_to_dots4(base_x_mm + mm_x + SHIFT_X_MM)

def V(mm_y: float) -> bytes:
    return ESC + b"V" + mm_to_dots4(mm_y + SHIFT_Y_MM)

def enc_ascii_upper(s: str) -> bytes:
    return (
        s.upper()
         .replace("Ç", "C")
         .replace("Ã", "A")
         .replace("Á", "A")
         .replace("À", "A")
         .replace("Â", "A")
         .replace("É", "E")
         .replace("Ê", "E")
         .replace("Í", "I")
         .replace("Ó", "O")
         .replace("Ô", "O")
         .replace("Õ", "O")
         .replace("Ú", "U")
         .encode("ascii", errors="ignore")
    )

def TXT(text: str) -> bytes:
    return (
        ESC + f"P{FONT_P}".encode("ascii") +
        ESC + b"L" + FONT_L +
        ESC + TEXT_FONT +
        enc_ascii_upper(text)
    )

def TXT_CUSTOM(text: str, font: bytes, font_p: int, font_l: bytes) -> bytes:
    return (
        ESC + f"P{font_p}".encode("ascii") +
        ESC + b"L" + font_l +
        ESC + font +
        enc_ascii_upper(text)
    )

def TXT_BIG(text: str) -> bytes:
    # fonte maior (ajuste fino aqui)
    return TXT_CUSTOM(text, font=b"XM", font_p=2, font_l=b"0400")

def TXT_MED(text: str) -> bytes:
    return TXT_CUSTOM(text, font=b"XS", font_p=1, font_l=b"0250")

def TXT_SMALL(text: str) -> bytes:
    return TXT_CUSTOM(text, font=b"XS", font_p=1, font_l=b"0200")

def load_logo_sbpl(path: str) -> bytes:
    with open(path, "rb") as f:
        return f.read()
    
def load_logo_sbpl_clean(path: str) -> bytes:
    with open(path, "rb") as f:
        raw = f.read()

    start = raw.find(ESC + b"GH")
    if start == -1:
        raise RuntimeError("GH NAO ENCONTRADO NO ARQUIVO")

    # remove qualquer ESC Q / ESC Z depois
    end = raw.find(ESC + b"Q", start)
    if end == -1:
        return raw[start:]

    return raw[start:end]

def sbpl_label(payload: dict) -> bytes:
    base_x_mm = 0.0 if SIDE.lower() == "left" else (LABEL_W_MM + GAP_MM)

    deveui = payload.get("deveui", "").replace(":", "").lower()
    appkey = payload.get("appkey", "").replace(":", "").lower()
    model  = payload.get("model", "").upper()
    lote = payload.get("lote", "")

    lote   = payload.get("lote", "000000")
    serial = deveui

    info = label_info_for(model)

    # QR compacto (ASCII puro). appkey só entra se existir (modelos GSM não têm).
    qr_obj   = {"deveui": deveui, "model": model}
    if appkey:
        qr_obj["appkey"] = appkey
    qr_text  = json.dumps(qr_obj, separators=(",", ":"))
    qr_bytes = qr_text.encode("ascii")
    mmmm     = f"{len(qr_bytes):04d}".encode("ascii")

    data = b""
    data += ESC + b"A"
    data += ESC + f"CS{SPEED_IPS}".encode()
    data += ESC + f"#F{DARKNESS}A".encode()

    # Logo (GH gerado no SATO Tools)
    try:
        logo_path = os.path.join(get_print_dir(), "logo_sbpl.txt")
        logo_sbpl = load_logo_sbpl_clean(logo_path)
        data += ESC + b"S"
        # POSICAO AJUSTADA PARA 40x25
        data += H(0.8, base_x_mm) + V(1.0)
        data += logo_sbpl
    except Exception as e:
        print(f"[PRINT] Logo não carregada: {e}")

    # QR Code
    data += H(QR_X_MM, base_x_mm) + V(QR_Y_MM)
    data += ESC + b"2D30" + f",L,{QR_MODULE:02d},1,0".encode()
    data += ESC + b"DN" + mmmm + b"," + qr_bytes

    # Texto
    x  = 1.4
    y  = 6.2
    dy = 2.5

    data += H(x, base_x_mm) + V(y) + TXT("MODULO DE TELEMEDICAO"); y += dy
    data += H(x, base_x_mm) + V(y) + TXT(f"MODELO: {model}");        y += dy
    data += H(x, base_x_mm) + V(y) + TXT(f"VERSAO: {info['version']}");            y += dy
    data += H(x, base_x_mm) + V(y) + TXT(f"ALIMENTACAO: {info['power']}");   y += dy
    data += H(x, base_x_mm) + V(y) + TXT(f"LOTE: {lote}  SERIAL: {serial}")
    

    # Rodape
    data += H(12.0, base_x_mm) + V(19.4) + TXT("FABRICADO NO BRASIL")
    data += H(17.0, base_x_mm) + V(22.0) + TXT(datetime.now().strftime("%m/%Y"))

    data += ESC + b"Q1"
    data += ESC + b"Z"
    return data

def print_raw(printer_name: str, payload: bytes):
    h = win32print.OpenPrinter(printer_name)
    try:
        win32print.StartDocPrinter(h, 1, ("SEAIOT_LABEL_40x25", None, "RAW"))
        win32print.StartPagePrinter(h)
        win32print.WritePrinter(h, payload)
        win32print.EndPagePrinter(h)
        win32print.EndDocPrinter(h)
    finally:
        win32print.ClosePrinter(h)

def print_label(payload: dict):
    """
    payload esperado:
    {
        "deveui": "...",
        "appkey": "...",
        "model":  "...",
        "lote":   "000001"   # opcional por enquanto
    }
    """
    data = sbpl_label(payload)
    print_raw(PRINTER, data)
    print("ENVIADO.")

def sbpl_box_closure_label(box_id: str, lote: str, model: str, quantity: int) -> bytes:
    base_x_mm = 0.0 if SIDE.lower() == "left" else (LABEL_W_MM + GAP_MM)

    box_id   = (box_id or "").strip()
    lote     = (lote or "000000").strip()
    model    = (model or "").strip().upper()
    quantity = int(quantity) if quantity is not None else 100

    dt_str = datetime.now().strftime("%d/%m/%Y %H:%M")

    data = b""
    data += ESC + b"A"
    data += ESC + f"CS{SPEED_IPS}".encode()
    data += ESC + f"#F{DARKNESS}A".encode()

    # (Opcional) Logo pequeno
    try:
        logo_path = os.path.join(get_print_dir(), "logo_sbpl.txt")
        logo_sbpl = load_logo_sbpl_clean(logo_path)
        data += ESC + b"S"
        data += H(0.8, base_x_mm) + V(1.0)
        data += logo_sbpl
    except Exception:
        pass

    x = 1.0

    data += H(x, base_x_mm) + V(8.0) + TXT_BIG(f"CAIXA {box_id}")
    data += H(x, base_x_mm) + V(11.0) + TXT_BIG(f"LOTE {lote}")
    data += H(x, base_x_mm) + V(14.0) + TXT_BIG(f"MODELO {model}")
    data += H(x, base_x_mm) + V(17.0) + TXT_BIG(f"QTD {quantity}")
    data += H(x, base_x_mm) + V(21.0) + TXT_BIG(dt_str)

    data += ESC + b"Q1"
    data += ESC + b"Z"
    return data


def print_box_closure_label(box_id: str, lote: str, model: str, quantity: int):
    data = sbpl_box_closure_label(box_id, lote, model, quantity)
    # doc name diferente só pra facilitar debug/spool
    h = win32print.OpenPrinter(PRINTER)
    try:
        win32print.StartDocPrinter(h, 1, ("SEAIOT_BOX_CLOSURE", None, "RAW"))
        win32print.StartPagePrinter(h)
        win32print.WritePrinter(h, data)
        win32print.EndPagePrinter(h)
        win32print.EndDocPrinter(h)
    finally:
        win32print.ClosePrinter(h)


if __name__ == "__main__":
    print_box_closure_label("000002", "000001", "SI-EMR", 100)
    print("TESTE ENVIADO")
