const { exec } = require("child_process");
const fs = require("fs");
const path = require("path");
const os = require("os");

/**
 * Send raw ESC/POS bytes to a Windows printer queue via a small PowerShell helper.
 * Uses .NET RawPrinterHelper pattern (WritePrinter) to avoid corrupting binary data.
 */
function printRawFileToWindowsQueue(printerName, filePath) {
  return new Promise((resolve, reject) => {
    const psScript = `
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class RawPrinterHelper {
  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
  public class DOCINFOA {
    [MarshalAs(UnmanagedType.LPStr)] public string pDocName;
    [MarshalAs(UnmanagedType.LPStr)] public string pOutputFile;
    [MarshalAs(UnmanagedType.LPStr)] public string pDataType;
  }
  [DllImport("winspool.drv", SetLastError=true, CharSet=CharSet.Ansi)]
  public static extern bool OpenPrinter(string szPrinter, out IntPtr hPrinter, IntPtr pd);
  [DllImport("winspool.drv", SetLastError=true)]
  public static extern bool ClosePrinter(IntPtr hPrinter);
  [DllImport("winspool.drv", SetLastError=true, CharSet=CharSet.Ansi)]
  public static extern bool StartDocPrinter(IntPtr hPrinter, int level, [In] DOCINFOA di);
  [DllImport("winspool.drv", SetLastError=true)]
  public static extern bool EndDocPrinter(IntPtr hPrinter);
  [DllImport("winspool.drv", SetLastError=true)]
  public static extern bool StartPagePrinter(IntPtr hPrinter);
  [DllImport("winspool.drv", SetLastError=true)]
  public static extern bool EndPagePrinter(IntPtr hPrinter);
  [DllImport("winspool.drv", SetLastError=true)]
  public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, int dwCount, out int dwWritten);
}
"@
$printerName = ${JSON.stringify(printerName)}
$filePath = ${JSON.stringify(filePath)}
$bytes = [System.IO.File]::ReadAllBytes($filePath)
$h = [IntPtr]::Zero
if (-not [RawPrinterHelper]::OpenPrinter($printerName, [ref]$h, [IntPtr]::Zero)) { throw "OpenPrinter failed" }
try {
  $di = New-Object RawPrinterHelper+DOCINFOA
  $di.pDocName = "Siraya Receipt"
  $di.pDataType = "RAW"
  if (-not [RawPrinterHelper]::StartDocPrinter($h, 1, $di)) { throw "StartDocPrinter failed" }
  try {
    if (-not [RawPrinterHelper]::StartPagePrinter($h)) { throw "StartPagePrinter failed" }
  $p = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($bytes.Length)
  [System.Runtime.InteropServices.Marshal]::Copy($bytes, 0, $p, $bytes.Length)
  $written = 0
  if (-not [RawPrinterHelper]::WritePrinter($h, $p, $bytes.Length, [ref]$written)) { throw "WritePrinter failed" }
  [System.Runtime.InteropServices.Marshal]::FreeHGlobal($p)
    if (-not [RawPrinterHelper]::EndPagePrinter($h)) { throw "EndPagePrinter failed" }
  } finally {
    [void][RawPrinterHelper]::EndDocPrinter($h)
  }
} finally {
  [void][RawPrinterHelper]::ClosePrinter($h)
}
`;

    const scriptPath = path.join(
      os.tmpdir(),
      `siraya-raw-print-${Date.now()}.ps1`,
    );
    fs.writeFileSync(scriptPath, psScript, "utf8");

    exec(
      `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}"`,
      { timeout: 30000, windowsHide: true },
      (error, stdout, stderr) => {
        try {
          fs.unlinkSync(scriptPath);
        } catch {
          /* ignore */
        }
        if (error) {
          reject(
            new Error(
              stderr?.trim() || error.message || "Windows raw print failed",
            ),
          );
        } else {
          resolve(stdout);
        }
      },
    );
  });
}

module.exports = { printRawFileToWindowsQueue };
