// PRUEBA DEL BLOQUE 8: EL RESPALDO CIFRADO (2026-07-28)
// Se prueban las dos cosas que tienen que cumplirse a la vez: que el respaldo
// sirva para recuperar el libro completo, y que no sea una copia de las
// facturas de los clientes tirada por ahi (000102 art. 25, confidencialidad).
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { LibroFiscal } from '../dist/libro.js';
import { RespaldoCifrado } from '../dist/respaldo.js';
import { armarDocumento } from '../dist/armador.js';

let fallos = 0;
const check = (cond, msg) => {
  console.log((cond ? '  OK  ' : '  XX  ') + msg);
  if (!cond) fallos++;
};
const dir = mkdtempSync(join(tmpdir(), 'fiscal-resp-'));
const RUTA_LIBRO = join(dir, 'libro.jsonl');
const RUTA_RESP = join(dir, 'respaldo.enc');
const FRASE = 'arepa-power-respaldo-2026';

const EMISOR = {
  rif: 'J-50856106-6',
  razon_social: 'Arepa Power de prueba',
  domicilio_fiscal: 'Araure',
  precios_con_iva: true,
  alicuota_general: 16,
};
const venta = (id, cliente) => ({
  origen_id: id,
  canal: 'mesa',
  cliente: { nombre: cliente, cedula: 'V-22606827' },
  renglones: [{ nombre: 'Arepa Dominó', cantidad: 1, precio_usd: 5, alicuota: 16 }],
  tasa_bs: 742.23,
  pago: { metodo: 'efectivo' },
});

try {
  const libro = new LibroFiscal({ ruta: RUTA_LIBRO, serie: 'A', equipo: 'FISCAL-01' });
  libro.asentar('factura', armarDocumento(venta('v1', 'Maria Rodriguez'), EMISOR));
  libro.asentar('factura', armarDocumento(venta('v2', 'Pedro Gonzalez'), EMISOR));

  console.log('\n== 1. La frase de recuperacion no puede ser cualquier cosa ==');
  let corta = false;
  try {
    new RespaldoCifrado(join(dir, 'x.enc'), '1234');
  } catch {
    corta = true;
  }
  check(corta, 'una frase de cuatro digitos se rechaza');

  console.log('\n== 2. El respaldo guarda todo el libro ==');
  const resp = new RespaldoCifrado(RUTA_RESP, FRASE);
  const nuevos = resp.ponerseAlDia(libro.todos());
  check(nuevos === 2, `mete los 2 asientos que habia (${nuevos})`);
  check(resp.comparar(libro.todos()).alDia, 'y queda al dia con el libro');

  console.log('\n== 3. NADIE puede leer las facturas del respaldo sin la frase ==');
  const crudo = readFileSync(RUTA_RESP, 'utf8');
  check(!crudo.includes('Maria Rodriguez'), 'el nombre del cliente NO aparece en el archivo');
  check(!crudo.includes('Arepa Dominó'), 'ni lo que se vendio');
  check(!crudo.includes('J-50856106-6'), 'ni el RIF del negocio');
  check(!crudo.includes('22606827'), 'ni la cedula del cliente');

  console.log('\n== 4. Con la frase correcta, se recupera identico ==');
  const restaurado = resp.restaurar();
  check(restaurado.length === 2, `salen los 2 asientos (${restaurado.length})`);
  check(restaurado[0].hash === libro.todos()[0].hash, 'con el mismo sello que tenian en el libro');
  check(restaurado[0].documento.cliente.nombre === 'Maria Rodriguez', 'y con sus datos completos');

  console.log('\n== 5. Con la frase equivocada, no abre ==');
  let mensaje = '';
  try {
    new RespaldoCifrado(RUTA_RESP, 'esta-no-es-la-frase-correcta').restaurar();
  } catch (e) {
    mensaje = e.message;
  }
  check(/frase de recuperacion no corresponde|alterado/i.test(mensaje), `avisa claro: "${mensaje.slice(0, 70)}..."`);

  console.log('\n== 6. Solo agrega: lo viejo no se reescribe ==');
  const antes = readFileSync(RUTA_RESP, 'utf8');
  libro.asentar('factura', armarDocumento(venta('v3', 'Ana Perez'), EMISOR));
  const resp2 = new RespaldoCifrado(RUTA_RESP, FRASE);
  resp2.ponerseAlDia(libro.todos());
  const despues = readFileSync(RUTA_RESP, 'utf8');
  check(despues.startsWith(antes), 'el archivo nuevo empieza exactamente igual que el viejo');
  check(resp2.cuantos() === 3, `y ahora tiene 3 asientos (${resp2.cuantos()})`);

  console.log('\n== 7. Si alguien mete la mano en el respaldo, se nota ==');
  const lineas = readFileSync(RUTA_RESP, 'utf8').split('\n').filter(Boolean);
  const tocada = JSON.parse(lineas[1]);
  const bytes = Buffer.from(tocada.datos, 'base64');
  bytes[0] = bytes[0] ^ 0xff; // le cambiamos un byte al azar
  tocada.datos = bytes.toString('base64');
  lineas[1] = JSON.stringify(tocada);
  writeFileSync(RUTA_RESP, lineas.join('\n') + '\n');
  let detectado = false;
  try {
    new RespaldoCifrado(RUTA_RESP, FRASE).restaurar();
  } catch (e) {
    detectado = /alterado|no corresponde/i.test(e.message);
  }
  check(detectado, 'el respaldo alterado no se puede abrir y lo dice');

  console.log('\n== 8. Sirve de verdad para recuperarse de un desastre ==');
  // Se quema el disco: queda solo el respaldo (con el archivo sano de nuevo).
  writeFileSync(RUTA_RESP, antes);
  const soloRespaldo = new RespaldoCifrado(RUTA_RESP, FRASE);
  const recuperados = soloRespaldo.restaurar();
  check(recuperados.length === 2, `del respaldo salen los documentos (${recuperados.length})`);
  check(recuperados.every((a, i) => a.seq === i + 1), 'en orden y sin huecos en la numeracion');
  check(recuperados[1].documento.total_usd === 5, 'con los montos intactos');
} catch (e) {
  console.log('  XX  ' + e.message);
  fallos++;
} finally {
  rmSync(dir, { recursive: true, force: true });
}

console.log(fallos === 0 ? '\nBLOQUE 8 (RESPALDO CIFRADO): TODO VERDE' : `\n${fallos} FALLO(S)`);
process.exitCode = fallos === 0 ? 0 : 1; // salida natural: process.exit() con undici cerrando revienta libuv en Node 24/Windows
