#ifndef LP_API_H
#define LP_API_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32
  #ifdef LP_DLL_EXPORT
    #define LP_API __declspec(dllexport)
  #else
    #define LP_API __declspec(dllimport)
  #endif
#else
  #define LP_API
#endif

// Interface type constants
#define LP_DRIVER    0
#define LP_USB       1
#define LP_NET       2
#define LP_RFID_USB  4
#define LP_RFID_NET  5
#define LP_GBGM_USB  6
#define LP_GBGM_NET  7
#define LP_GJB_USB   8
#define LP_GJB_NET   9

// Object type constants
#define LP_OBJ_TEXT     0
#define LP_OBJ_BARCODE  1
#define LP_OBJ_LINE     2
#define LP_OBJ_RECT     3
#define LP_OBJ_IMAGE    4
#define LP_OBJ_RFID     5

// Opaque handles
typedef struct LP_PrinterImpl* LP_PRINTER;
typedef struct LP_LabelImpl*   LP_LABEL;       // Label layout + object list
typedef struct LP_LabelDocImpl* LP_LABELDOC;   // Label document (from LSF file)

// USB printer info
typedef struct {
    char printerName[64];
    char portName[32];
    char serialNo[32];
} LP_USBINFO;

// ============================================================================
// Label Layout (LP_LABEL)
// ============================================================================
LP_LABEL    LP_API LpLabel_Create(void);
void        LP_API LpLabel_Destroy(LP_LABEL label);

void LP_API LpLabel_SetWidth(LP_LABEL label, float widthMm);
void LP_API LpLabel_SetHeight(LP_LABEL label, float heightMm);
void LP_API LpLabel_SetRowGap(LP_LABEL label, float gapMm);
void LP_API LpLabel_SetColumnGap(LP_LABEL label, float gapMm);
void LP_API LpLabel_SetRowCount(LP_LABEL label, int count);
void LP_API LpLabel_SetColumnCount(LP_LABEL label, int count);
void LP_API LpLabel_SetLeftOffset(LP_LABEL label, float offsetMm);
void LP_API LpLabel_SetTopOffset(LP_LABEL label, float offsetMm);
void LP_API LpLabel_SetPageLeftEdges(LP_LABEL label, float edgesMm);
void LP_API LpLabel_SetPageRightEdges(LP_LABEL label, float edgesMm);
void LP_API LpLabel_SetStartLocation(LP_LABEL label, int location);
void LP_API LpLabel_SetLabelOrder(LP_LABEL label, int order);
void LP_API LpLabel_SetLabelShape(LP_LABEL label, int shape);

float LP_API LpLabel_GetWidth(LP_LABEL label);
float LP_API LpLabel_GetHeight(LP_LABEL label);
float LP_API LpLabel_GetRowGap(LP_LABEL label);
float LP_API LpLabel_GetColumnGap(LP_LABEL label);
int   LP_API LpLabel_GetRowCount(LP_LABEL label);
int   LP_API LpLabel_GetColumnCount(LP_LABEL label);
float LP_API LpLabel_GetLeftOffset(LP_LABEL label);
float LP_API LpLabel_GetTopOffset(LP_LABEL label);
float LP_API LpLabel_GetPageLeftEdges(LP_LABEL label);
float LP_API LpLabel_GetPageRightEdges(LP_LABEL label);
int   LP_API LpLabel_GetStartLocation(LP_LABEL label);
int   LP_API LpLabel_GetLabelOrder(LP_LABEL label);
int   LP_API LpLabel_GetLabelShape(LP_LABEL label);

// ============================================================================
// Programmatic Objects (LP_LABEL)
// ============================================================================

// Add text object
//   textType: 0=single line, 1=paragraph (auto wrap/shrink/compress)
//   textWidthMm: max paragraph width in mm (ignored for single line, pass 0)
int LP_API LpLabel_AddText(LP_LABEL label, const char* name,
                            const char* data, float xMm, float yMm,
                            float fontSize, const char* fontName,
                            int textType, float textWidthMm);

// Add barcode object
//   textPosition: 0=below, 1=above, 2=no text
int LP_API LpLabel_AddBarcode(LP_LABEL label, const char* name,
                               const char* data, float xMm, float yMm,
                               const char* barcodeKind, float scale,
                               float heightMm, int textPosition);

// Set barcode text properties (by object index)
//   textOffset: gap between barcode and text in mm
//   textAlign: 0=left, 1=right, 2=center, 3=justify
int LP_API LpLabel_SetBarcodeText(LP_LABEL label, int index,
                                   const char* textFont, float fontSize,
                                   float textOffset, int textAlign);

// Add line / rectangle objects
int LP_API LpLabel_AddLine(LP_LABEL label, const char* name,
                            float startX, float startY,
                            float endX, float endY, float lineWidth);
int LP_API LpLabel_AddRect(LP_LABEL label, const char* name,
                            float startX, float startY,
                            float endX, float endY, float lineWidth);

// Line dash style: 0=solid, 1=dash, 2=dash-dot, 3=dash-dot-dot, 4=dot
int LP_API LpLabel_SetLineDash(LP_LABEL label, int index, int dashStyle);

// Rectangle shape: 0=normal rect, 1=rounded rect, 2=ellipse, 3=triangle
int LP_API LpLabel_SetRectShape(LP_LABEL label, int index, int rectClass);
int LP_API LpLabel_SetRectRadius(LP_LABEL label, int index, float cornerRadius);
int LP_API LpLabel_SetRectFill(LP_LABEL label, int index, int fill);

// Add image object (imageBase64 = base64-encoded JPEG/PNG/BMP data)
int LP_API LpLabel_AddImage(LP_LABEL label, const char* name,
                             float xMm, float yMm, float scale,
                             const char* imageBase64);
int LP_API LpLabel_SetImageScale(LP_LABEL label, int index,
                                  float hScale, float vScale);

// Add RFID object
//   encoderType: 0=UHF, 1=HF 15693, 2=HF 14443A, 3=HF NFC
//   dataType: 0=text, 1=hex, 2=URL (NDEF), 3=plain text (NDEF)
//   dataBlock: 0=EPC (UHF), 1=USER (UHF)
int LP_API LpLabel_AddRfid(LP_LABEL label, const char* name,
                            const char* data,
                            int encoderType, int dataType, int dataBlock);
// HF RFID parameters: startBlock=write start block, modulePower=0(12db)~3(48db)
int LP_API LpLabel_SetRfidHf(LP_LABEL label, int index,
                              int startBlock, int modulePower);

// Text properties setters
int LP_API LpLabel_SetTextAlign(LP_LABEL label, int index, int align);
int LP_API LpLabel_SetFontStyle(LP_LABEL label, int index, int fontStyle);

// ============================================================================
// Programmatic Render & Print (LP_LABEL)
// ============================================================================
int LP_API LpLabel_Render(LP_LABEL label, LP_PRINTER printer, int pageIndex,
                           uint8_t** outPixels, int* outWidth,
                           int* outHeight, int* outStride);
int LP_API LpLabel_SavePreview(LP_LABEL label, LP_PRINTER printer,
                                const char* filePath);
int LP_API LpLabel_Print(LP_LABEL label, LP_PRINTER printer);
int LP_API LpLabel_PrintBlankPage(LP_LABEL label, LP_PRINTER printer,
                                   int printErrorFlag);

// ============================================================================
// Printer Management
// ============================================================================
LP_PRINTER  LP_API LpPrinter_Create(void);
void        LP_API LpPrinter_Destroy(LP_PRINTER printer);

int  LP_API LpPrinter_Connect(LP_PRINTER printer);
void LP_API LpPrinter_Disconnect(LP_PRINTER printer);

void LP_API LpPrinter_SetInterface(LP_PRINTER printer, int interfaceType);
void LP_API LpPrinter_SetUsbSerial(LP_PRINTER printer, const char* serialNo);
void LP_API LpPrinter_SetNetAddress(LP_PRINTER printer, const char* ip);
void LP_API LpPrinter_SetName(LP_PRINTER printer, const char* printerName);
void LP_API LpPrinter_SetDpi(LP_PRINTER printer, int dpi);
void LP_API LpPrinter_SetSpeed(LP_PRINTER printer, int speed);
void LP_API LpPrinter_SetDarkness(LP_PRINTER printer, int darkness);
void LP_API LpPrinter_SetPageDirection(LP_PRINTER printer, int direction);

int  LP_API LpPrinter_EnumUsb(LP_USBINFO* infos, int maxCount);
int  LP_API LpPrinter_GetStatusCode(LP_PRINTER printer);
int  LP_API LpPrinter_GetStatusInfo(int statusCode, char* buf, int bufSize);

// ============================================================================
// Label Document (LP_LABELDOC) - LSF file operations
// ============================================================================
LP_LABELDOC LP_API LpLabelDoc_Load(const char* filePath);
LP_LABELDOC LP_API LpLabelDoc_LoadFromMemory(const uint8_t* data, int len);
void        LP_API LpLabelDoc_Destroy(LP_LABELDOC doc);
LP_API const char* LpLabelDoc_GetLastError(void);

int   LP_API LpLabelDoc_GetPrinterDpi(LP_LABELDOC doc);
void  LP_API LpLabelDoc_AdjustDpiScale(LP_LABELDOC doc, int oldDpi, int newDpi);
int   LP_API LpLabelDoc_GetPrinterSpeed(LP_LABELDOC doc);
int   LP_API LpLabelDoc_GetPrinterDarkness(LP_LABELDOC doc);
int   LP_API LpLabelDoc_GetPrinterPageDirection(LP_LABELDOC doc);
int   LP_API LpLabelDoc_GetPrinterHaveGap(LP_LABELDOC doc);

void  LP_API LpLabelDoc_SetPrintCount(LP_LABELDOC doc, int count);
void  LP_API LpLabelDoc_SetCopyCount(LP_LABELDOC doc, int copies);
void  LP_API LpLabelDoc_SetReverse(LP_LABELDOC doc, int reverse);

// ============================================================================
// Label Objects (from LSF document)
// ============================================================================
int   LP_API LpLabelDoc_GetObjectCount(LP_LABELDOC doc);
int   LP_API LpLabelDoc_GetObjectType(LP_LABELDOC doc, int index);
int   LP_API LpObject_GetName(LP_LABELDOC doc, int index, char* buf, int bufSize);
float LP_API LpObject_GetX(LP_LABELDOC doc, int index);
float LP_API LpObject_GetY(LP_LABELDOC doc, int index);
int   LP_API LpObject_GetData(LP_LABELDOC doc, int index, char* buf, int bufSize);
int   LP_API LpObject_GetCodeData(LP_LABELDOC doc, int index, char* buf, int bufSize);
int   LP_API LpObject_GetBarcodeKind(LP_LABELDOC doc, int index, char* buf, int bufSize);
int   LP_API LpObject_GetDataChildIDs(LP_LABELDOC doc, int index, char* buf, int bufSize);
int   LP_API LpObject_GetVarCount(LP_LABELDOC doc, int index);
int   LP_API LpObject_GetVarInfo(LP_LABELDOC doc, int index, int varIndex,
                                  char* nameBuf, int nameSize,
                                  char* dataBuf, int dataSize,
                                  int* outId, int* outType, int* outEnable);
int   LP_API LpObject_SetVariable(LP_LABELDOC doc, int index, const char* name, const char* value);
int   LP_API LpObject_SetVariableAll(LP_LABELDOC doc, const char* name, const char* value);

// ============================================================================
// Render & Print (LP_LABELDOC)
// ============================================================================
int LP_API LpLabelDoc_Render(LP_LABELDOC doc, LP_PRINTER printer, int pageIndex,
                              uint8_t** outPixels, int* outWidth,
                              int* outHeight, int* outStride);
int LP_API LpLabelDoc_SavePreview(LP_LABELDOC doc, LP_PRINTER printer,
                                   const char* filePath);
int LP_API LpLabelDoc_Print(LP_LABELDOC doc, LP_PRINTER printer);
int LP_API LpLabelDoc_PrintBlankPage(LP_LABELDOC doc, LP_PRINTER printer,
                                      int printErrorFlag);

// ============================================================================
// RFID
// ============================================================================

// Read UHF tag data
//   area: 0=TID, 1=EPC, 2=TID+EPC, 3=USER
//   feed: paper feed after read (0=original, 1=tear-off, 2=print line, 3=antenna)
//   timeoutMs: timeout in ms, suggest 2000
//   Returns: >0=data length, 0=no tag, -1=failure
int LP_API LpPrinter_ReadUHFTag(LP_PRINTER printer, int area, int feed,
                                 int timeoutMs, char* buf, int bufSize);

// Read HF tag data (15693 / 14443A / NFC)
//   protocol: 1=15693, 2=14443A, 3=NFC
//   area: 0=UID, 1=data area
//   startblock: read start block address
//   timeoutMs: timeout in ms, suggest 5000
//   Returns: >0=data length, 0=no tag, -1=failure
int LP_API LpPrinter_ReadHFTag(LP_PRINTER printer, int protocol, int area,
                                int startblock,
                                int timeoutMs, char* buf, int bufSize);

// ============================================================================
// Memory & Error
// ============================================================================
void        LP_API LpFree(void* ptr);
int         LP_API LpGetLastErrorCode(void);
LP_API const char* LpGetLastErrorMessage(void);

#ifdef __cplusplus
}
#endif

#endif // LP_API_H
