// Impresora termica VIRTUAL: escucha TCP como una impresora real (puerto 9100)
// y decodifica el ESC/POS a texto legible. Para probar el cerebrito sin hardware.
// Modo suelto:  node test/impresora_virtual.mjs 9100
import { createServer } from 'node:net';

const CP850_INV = {
  0xa0: 'á', 0x82: 'é', 0xa1: 'í', 0xa2: 'ó', 0xa3: 'ú', 0xa4: 'ñ', 0xa5: 'Ñ',
  0xb5: 'Á', 0x90: 'É', 0xd6: 'Í', 0xe0: 'Ó', 0xe9: 'Ú', 0x81: 'ü', 0x9a: 'Ü',
  0xa8: '¿', 0xad: '¡', 0xf8: '°', 0xfa: '·',
};

/** Traduce bytes ESC/POS a texto legible (marca el corte como [CORTE]). */
export function decodificar(buf) {
  let out = '';
  let i = 0;
  while (i < buf.length) {
    const b = buf[i];
    if (b === 0x1b) {
      const c = buf[i + 1];
      if (c === 0x40) i += 2; // reset
      else if (c === 0x74 || c === 0x61 || c === 0x45) i += 3; // codepage/alineacion/negrita
      else i += 2;
      continue;
    }
    if (b === 0x1d) {
      const c = buf[i + 1];
      if (c === 0x21) i += 3; // tamano
      else if (c === 0x56) {
        out += '[CORTE]\n';
        i += buf[i + 2] === 0x42 ? 4 : 3;
      } else i += 2;
      continue;
    }
    if (b === 0x0a) {
      out += '\n';
      i += 1;
      continue;
    }
    out += CP850_INV[b] ?? (b >= 32 && b < 127 ? String.fromCharCode(b) : '');
    i += 1;
  }
  return out;
}

/** Levanta una impresora virtual en 127.0.0.1:puerto. Acumula los tickets decodificados. */
export function crearImpresoraVirtual(puerto, alRecibir) {
  const tickets = [];
  const server = createServer((sock) => {
    const trozos = [];
    sock.on('data', (d) => trozos.push(d));
    sock.on('end', () => {
      const texto = decodificar(Buffer.concat(trozos));
      tickets.push(texto);
      alRecibir?.(texto);
    });
    sock.on('error', () => {
      /* cliente cortado a mitad: ignorar */
    });
  });
  return new Promise((resolve, reject) => {
    server.on('error', reject);
    server.listen(puerto, '127.0.0.1', () =>
      resolve({
        puerto,
        tickets,
        cerrar: () => new Promise((r) => server.close(() => r())),
      }),
    );
  });
}

// Modo suelto: imprime a consola todo lo que llegue.
if (process.argv[1] && process.argv[1].includes('impresora_virtual')) {
  const puerto = Number(process.argv[2] ?? 9100);
  await crearImpresoraVirtual(puerto, (texto) => {
    console.log(`\n===== TICKET (puerto ${puerto}) =====`);
    console.log(texto);
  });
  console.log(`Impresora virtual escuchando en 127.0.0.1:${puerto} (Ctrl+C para salir)`);
}
