// PRUEBA DE LA PUERTA DE LA IMPRENTA (2026-07-28)
// El caso del cliente que YA tiene su sistema homologado y solo necesita quien
// le numere sus ventas electronicas: manda su documento con su llave y recibe
// el numero de control y la direccion del sello. No instala nada nuestro.
// Corre contra la BD viva y la puerta publicada. Limpia todo.
import { readFileSync } from 'node:fs';

const REF = 'szzhhlevtrcambcoytiz';
const PAT = readFileSync(new URL('../.sb_token', import.meta.url), 'utf8').trim();
const PUERTA = process.env.PUERTA ?? 'https://sello.gustitoxpress.app';

let fallos = 0;
const check = (cond, msg) => {
  console.log((cond ? '  OK  ' : '  XX  ') + msg);
  if (!cond) fallos++;
};

async function sql(query) {
  const r = await fetch(`https://api.supabase.com/v1/projects/${REF}/database/query`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${PAT}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ query }),
  });
  const t = await r.text();
  if (!r.ok) throw new Error(t.slice(0, 200));
  return JSON.parse(t);
}

// RIF DE PRUEBAS, JAMAS el de un cliente real de la imprenta: la limpieza de
// este test borra el emisor COMPLETO. El 2026-07-31 una corrida con
// J-50856106-6 (ya dado de alta real como EF-00006-0) barrio el alta del
// piloto: llaves, respaldo del libro y estacion. Ademas, limpiar() ahora
// ABORTA si el RIF tiene libro respaldado en la nube.
const RIF = 'V-22606827-5';
const lit = (s) => `'${String(s).replace(/'/g, "''")}'`;

const limpiar = async () => {
  const real = await sql(`select count(*)::int as n from fiscal.respaldo r join fiscal.emisores e on e.id = r.emisor_id where e.rif = ${lit(RIF)}`);
  if (real[0]?.n > 0) throw new Error(`FRENO: el emisor ${RIF} tiene ${real[0].n} lineas de libro respaldadas: es un cliente REAL, este test no lo toca`);
  return sql(`delete from fiscal.intentos where quien = ${lit(RIF)};
       delete from fiscal.llaves where emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)});
       delete from fiscal.consultas_qr where token in (select token from fiscal.documentos d join fiscal.emisores e on e.id=d.emisor_id where e.rif=${lit(RIF)});
       delete from fiscal.documentos where emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)});
       delete from fiscal.series where emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)});
       delete from fiscal.emisores where rif=${lit(RIF)};`);
};

const emitir = (llave, cambios = {}) =>
  fetch(`${PUERTA}/api/emitir`, {
    method: 'POST',
    headers: { authorization: `Bearer ${llave}`, 'content-type': 'application/json' },
    body: JSON.stringify({
      rif: RIF,
      serie: 'B',
      tipo: 'factura',
      numero_documento: 501,
      hash: 'doc-del-cliente-501',
      fecha: new Date().toISOString(),
      base_bs: 10000,
      iva_bs: 1600,
      total_bs: 11600,
      documento: { origen: 'sistema del cliente', renglones: [{ nombre: 'Servicio' }] },
      ...cambios,
    }),
  });

try {
  await limpiar();
  await sql(`insert into fiscal.emisores (rif, razon_social, domicilio_fiscal, llave_hash)
             values (${lit(RIF)}, 'Empresa con sistema propio', 'Araure', 'sin-uso')`);

  console.log('\n== 1. Sin llave no se emite nada ==');
  const sinLlave = await fetch(`${PUERTA}/api/emitir`, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ rif: RIF }),
  });
  check(sinLlave.status === 401, `responde no autorizado (HTTP ${sinLlave.status})`);

  console.log('\n== 2. La llave se entrega UNA vez y se guarda hasheada ==');
  const llave = (await sql(`select fiscal.crear_llave(${lit(RIF)}, 'sistema administrativo del cliente') as k`))[0].k;
  check(llave.startsWith('gxf_'), `la llave sale con su prefijo (${llave.slice(0, 12)}...)`);
  const guardado = (await sql(`select llave_hash from fiscal.llaves where emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)})`))[0].llave_hash;
  check(!guardado.includes(llave.slice(4)), 'y en la base NO queda la llave en claro');

  console.log('\n== 3. Con la llave, el cliente emite ==');
  const r1 = await emitir(llave);
  const d1 = await r1.json();
  check(r1.status === 200, `la puerta responde (HTTP ${r1.status})`);
  check(Number(d1.numero_control) === 1, `le asigna el numero de control (${d1.numero_control})`);
  check(String(d1.sello).startsWith('https://sello.gustitoxpress.app/v/'), `y le devuelve el sello para su factura (${String(d1.sello).slice(0, 45)}...)`);
  check(d1.ya_estaba === false, 'avisando que es la primera vez');

  console.log('\n== 4. Si reintenta, NO se numera dos veces ==');
  const r2 = await (await emitir(llave)).json();
  check(Number(r2.numero_control) === Number(d1.numero_control), `devuelve el mismo numero (${r2.numero_control})`);
  check(r2.ya_estaba === true, 'y avisa que ese documento ya estaba');
  check(r2.sello === d1.sello, 'con el mismo sello, para que el QR impreso siga sirviendo');

  console.log('\n== 5. Una llave inventada no entra ==');
  const mala = await emitir('gxf_estonoesunallavereal0000000000000000000000000000');
  check(mala.status === 401, `rebota (HTTP ${mala.status})`);
  const cuerpo = await mala.json();
  check(cuerpo.error === 'No autorizado', 'sin decir si fallo el RIF o la llave');

  console.log('\n== 6. Un documento incompleto se rechaza con mensaje util ==');
  const incompleto = await fetch(`${PUERTA}/api/emitir`, {
    method: 'POST',
    headers: { authorization: `Bearer ${llave}`, 'content-type': 'application/json' },
    body: JSON.stringify({ rif: RIF, serie: 'B' }),
  });
  const detalle = await incompleto.json();
  check(incompleto.status === 400, `avisa que falta informacion (HTTP ${incompleto.status})`);
  check(Array.isArray(detalle.faltan) && detalle.faltan.length > 0, `y dice exactamente que falta (${detalle.faltan?.slice(0, 3).join(', ')}...)`);

  console.log('\n== 7. El sello del cliente funciona igual que el nuestro ==');
  const sello = await fetch(d1.sello);
  const htmlSello = await sello.text();
  check(sello.status === 200, `el QR del cliente abre (HTTP ${sello.status})`);
  check(htmlSello.includes('Empresa con sistema propio'), 'y muestra a su emisor');
  check(!htmlSello.includes('Servicio'), 'sin destapar lo que vendio');

  console.log('\n== 8. Queda el rastro de quien emitio ==');
  const intentos = (await sql(`select entro, motivo from fiscal.intentos where quien=${lit(RIF)} order by en`))[0];
  check(!!intentos, 'los intentos quedan registrados');
  const usos = (await sql(`select ultimo_uso from fiscal.llaves where emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)})`))[0];
  check(!!usos.ultimo_uso, 'y la llave guarda cuando se uso por ultima vez');
} catch (e) {
  console.log('  XX  ' + String(e).slice(0, 200));
  fallos++;
} finally {
  await limpiar();
}

console.log(fallos === 0 ? '\nPUERTA DE LA IMPRENTA: TODO VERDE' : `\n${fallos} FALLO(S)`);
process.exit(fallos === 0 ? 0 : 1);
