// PRUEBA DE LOS BLOQUES 1 Y 2 (2026-07-28)
// Bloque 1: la configuracion del negocio no deja arrancar si falta algo, y el
// RIF se valida de verdad (nada de emitir cien documentos con el RIF mal).
// Bloque 2: el documento se traduce al formato de la imprenta digital, en
// BOLIVARES (asi se emite en Venezuela aunque el negocio cobre en dolares), y
// existe una imprenta de practica para probar el circuito sin gastar
// documentos reales.
import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { revisar, puedeOperar, guardarConfig, leerConfig, imprentaActiva } from '../dist/config.js';
import { crearImprenta, ImprentaPractica } from '../dist/imprenta.js';
import { armarPayloadHKA } from '../dist/imprenta_hka.js';
import { LibroFiscal } from '../dist/libro.js';
import { armarDocumento, armarNotaCredito } from '../dist/armador.js';

let fallos = 0;
const check = (cond, msg) => {
  console.log((cond ? '  OK  ' : '  XX  ') + msg);
  if (!cond) fallos++;
};
const cent = (n) => Math.round(Number(n) * 100);
const dir = mkdtempSync(join(tmpdir(), 'fiscal-cfg-'));

const CONFIG_BUENA = {
  emisor: {
    rif: 'j508561066',
    razon_social: '  Emprendimiento de prueba  ',
    domicilio_fiscal: 'Araure, Portuguesa',
    precios_con_iva: true,
    alicuota_general: 16,
  },
  serie: 'a',
  sucursal: '1',
  equipo: 'FISCAL-01',
  imprenta: { adaptador: 'practica', nombre: 'Practica' },
  respaldo: null,
  usando: 'imprenta',
};

try {
  console.log('\n== BLOQUE 1: la configuracion del negocio ==');
  check(!puedeOperar(null), 'sin configuracion, la estacion NO sella nada');
  const conRifMalo = { ...CONFIG_BUENA, emisor: { ...CONFIG_BUENA.emisor, rif: 'J-12345678-9' } };
  const f1 = revisar(conRifMalo);
  check(f1.some((f) => f.campo === 'rif'), `un RIF inventado se rechaza: "${f1.find((f) => f.campo === 'rif')?.problema}"`);
  const sinRazon = { ...CONFIG_BUENA, emisor: { ...CONFIG_BUENA.emisor, razon_social: '   ' } };
  check(revisar(sinRazon).some((f) => f.campo === 'razon_social'), 'sin razon social tampoco arranca');
  const serieMala = { ...CONFIG_BUENA, serie: 'A1' };
  check(revisar(serieMala).some((f) => f.campo === 'serie'), 'la serie solo admite letras');
  const alicuotaMala = { ...CONFIG_BUENA, emisor: { ...CONFIG_BUENA.emisor, alicuota_general: 12 } };
  check(revisar(alicuotaMala).some((f) => f.campo === 'alicuota_general'), 'una alicuota inventada (12%) se rechaza');
  const realSinClave = { ...CONFIG_BUENA, imprenta: { adaptador: 'hka', nombre: 'HKA', url: 'https://x' } };
  check(revisar(realSinClave).some((f) => f.campo === 'imprenta.acceso'), 'una imprenta real sin credenciales no pasa');

  console.log('\n== La configuracion buena se guarda y se limpia sola ==');
  const guardada = guardarConfig(dir, CONFIG_BUENA);
  check(guardada.emisor.rif === 'J-50856106-6', `el RIF queda normalizado (${guardada.emisor.rif})`);
  check(guardada.emisor.razon_social === 'Emprendimiento de prueba', 'la razon social sin espacios de mas');
  check(guardada.serie === 'A', 'la serie en mayuscula');
  const releida = leerConfig(dir);
  check(releida?.emisor.rif === 'J-50856106-6', 'y se puede volver a leer del disco');
  check(puedeOperar(releida), 'con eso la estacion ya puede sellar');

  console.log('\n== El salvavidas: segunda imprenta configurada ==');
  const conRespaldo = {
    ...guardada,
    respaldo: { adaptador: 'practica', nombre: 'Imprenta de respaldo' },
    usando: 'respaldo',
  };
  check(imprentaActiva(conRespaldo).nombre === 'Imprenta de respaldo', 'al pasar al respaldo, se usa la segunda');
  check(imprentaActiva(guardada).nombre === 'Practica', 'y por defecto se usa la principal');

  console.log('\n== BLOQUE 2: la imprenta de practica ==');
  const libro = new LibroFiscal({ ruta: join(dir, 'libro.jsonl'), serie: 'A', equipo: 'FISCAL-01' });
  const emisor = { ...guardada.emisor };
  const venta = {
    origen_id: 'venta-1',
    canal: 'mesa',
    cliente: { nombre: 'Consumidor final' },
    renglones: [
      { nombre: 'Arepa Dominó', cantidad: 2, precio_usd: 5, alicuota: 16 },
      { nombre: 'Agua', cantidad: 1, precio_usd: 1, alicuota: 0 },
    ],
    tasa_bs: 742.23,
    pago: { metodo: 'efectivo' },
  };
  const asiento = libro.asentar('factura', armarDocumento(venta, emisor));
  const practica = await crearImprenta({ adaptador: 'practica', nombre: 'Practica' });
  const acuse = await practica.emitir(asiento);
  check(practica.real === false, 'la de practica avisa que NO emite documentos validos');
  check(acuse.numeroControl.startsWith('PRACTICA-'), `y su numero de control lo dice claro (${acuse.numeroControl})`);

  console.log('\n== BLOQUE 2: traduccion al formato de la imprenta digital ==');
  const p = armarPayloadHKA(asiento).documentoElectronico;
  // El contrato REAL (swagger del demo, 2026-07-30): las cuatro secciones de
  // identidad van DENTRO de encabezado; los renglones, en la raiz.
  const enc = p.encabezado;
  check(!!enc && !!enc.identificacionDocumento && !!enc.vendedor && !!enc.comprador && !!enc.totales && !!p.detallesItems, 'arma el encabezado del contrato real y los renglones en la raiz');
  check(enc.identificacionDocumento.tipoDocumento === '01', `una factura va como tipo 01 (${enc.identificacionDocumento.tipoDocumento})`);
  check(enc.identificacionDocumento.moneda === 'VES', 'el documento se emite en bolivares');
  check(enc.vendedor.codigo === 'J-50856106-6', 'con el RIF del negocio');
  check(enc.comprador.razonSocial === 'Consumidor final', 'y el comprador identificado');
  check(enc.comprador.pais === 'VE', 'con el pais, que el contrato real exige');
  check(cent(enc.totales.totalAPagar) === cent(11 * 742.23), `el total va convertido a bolivares (${enc.totales.totalAPagar})`);
  check(cent(enc.totales.montoGravadoTotal) + cent(enc.totales.montoExentoTotal) + cent(enc.totales.totalIVA) === cent(enc.totales.totalAPagar), 'gravado + exento + IVA cuadra con el total');
  check(p.detallesItems.length === 2 && p.detallesItems[0].tasaIVA === 16 && p.detallesItems[1].tasaIVA === 0, 'cada renglon lleva su propia tasa');
  check(p.detallesItems[0].numeroLinea === '1' && p.detallesItems[1].numeroLinea === '2', 'los renglones van numerados');

  console.log('\n== Una nota de credito viaja como tipo 03 ==');
  const nc = libro.corregir({ tipo: 'factura', numero: 1 }, armarNotaCredito(asiento.documento, 'Cobro de mas'));
  const pnc = armarPayloadHKA(nc).documentoElectronico;
  check(pnc.encabezado.identificacionDocumento.tipoDocumento === '03', `la nota de credito va como 03 (${pnc.encabezado.identificacionDocumento.tipoDocumento})`);
  check(Number(pnc.encabezado.totales.totalAPagar) < 0, 'con el monto en negativo');
  check(nc.documento.motivo === 'Cobro de mas', 'y con el motivo escrito, como exige la norma');

  console.log('\n== Sin tasa del dia no se puede emitir ==');
  const libro2 = new LibroFiscal({ ruta: join(dir, 'libro2.jsonl'), serie: 'A', equipo: 'FISCAL-01' });
  const sinTasa = libro2.asentar('factura', armarDocumento({ ...venta, origen_id: 'v-sin-tasa', tasa_bs: null }, emisor));
  let exploto = false;
  try {
    armarPayloadHKA(sinTasa);
  } catch (e) {
    exploto = /tasa/i.test(e.message);
  }
  check(exploto, 'avisa claro que falta la tasa, en vez de mandar numeros malos');
} catch (e) {
  console.log('  XX  ' + e.message);
  fallos++;
} finally {
  rmSync(dir, { recursive: true, force: true });
}

console.log(fallos === 0 ? '\nBLOQUES 1 Y 2: 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
