//go:build windows

package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

// ---------------------------------------------------------------
// WinAPI - acesso direto à impressora via WritePrinter
// ---------------------------------------------------------------

var (
	winspool         = syscall.NewLazyDLL("winspool.drv")
	openPrinter      = winspool.NewProc("OpenPrinterW")
	closePrinter     = winspool.NewProc("ClosePrinter")
	startDocPrinter  = winspool.NewProc("StartDocPrinterW")
	endDocPrinter    = winspool.NewProc("EndDocPrinter")
	startPagePrinter = winspool.NewProc("StartPagePrinter")
	endPagePrinter   = winspool.NewProc("EndPagePrinter")
	writePrinter     = winspool.NewProc("WritePrinter")
)

// DOC_INFO_1 é a estrutura usada pelo StartDocPrinter
type DOC_INFO_1 struct {
	DocName    *uint16
	OutputFile *uint16
	DataType   *uint16 // "RAW" para envio direto de ZPL
}

// Impressora encapsula o handle da impressora Windows
type Impressora struct {
	handle uintptr
}

// AbrirImpressora abre a impressora pelo nome exato do Windows.
// Para descobrir o nome: Get-Printer | Select-Object Name (PowerShell)
func AbrirImpressora(nome string) (*Impressora, error) {
	nomePtr, err := syscall.UTF16PtrFromString(nome)
	if err != nil {
		return nil, err
	}

	var handle uintptr
	ret, _, err := openPrinter.Call(
		uintptr(unsafe.Pointer(nomePtr)),
		uintptr(unsafe.Pointer(&handle)),
		0,
	)
	if ret == 0 {
		return nil, fmt.Errorf("OpenPrinter falhou: %w", err)
	}

	return &Impressora{handle: handle}, nil
}

// Fechar fecha o handle da impressora
func (p *Impressora) Fechar() {
	closePrinter.Call(p.handle)
}

// EnviarZPL envia uma string ZPL diretamente para a impressora via RAW
func (p *Impressora) EnviarZPL(zpl string) error {
	// Nome do documento (aparece na fila de impressão)
	docName, _ := syscall.UTF16PtrFromString("Etiqueta ZPL")
	dataType, _ := syscall.UTF16PtrFromString("RAW")

	docInfo := DOC_INFO_1{
		DocName:    docName,
		OutputFile: nil,
		DataType:   dataType,
	}

	// Inicia o documento
	ret, _, err := startDocPrinter.Call(
		p.handle,
		1,
		uintptr(unsafe.Pointer(&docInfo)),
	)
	if ret == 0 {
		return fmt.Errorf("StartDocPrinter falhou: %w", err)
	}
	defer endDocPrinter.Call(p.handle)

	// Inicia a página
	ret, _, err = startPagePrinter.Call(p.handle)
	if ret == 0 {
		return fmt.Errorf("StartPagePrinter falhou: %w", err)
	}
	defer endPagePrinter.Call(p.handle)

	// Envia os bytes ZPL
	dados := []byte(zpl)
	var escritos uint32
	ret, _, err = writePrinter.Call(
		p.handle,
		uintptr(unsafe.Pointer(&dados[0])),
		uintptr(len(dados)),
		uintptr(unsafe.Pointer(&escritos)),
	)
	if ret == 0 {
		return fmt.Errorf("WritePrinter falhou: %w", err)
	}

	return nil
}

