// PRUEBA EN VIVO DEL DEPOSITO DEL RESPALDO (2026-07-29)
//
// La otra prueba (apps/fiscal/test/prueba_respaldo_afuera.mjs) usa una imprenta
// de mentira para probar la Estacion. Esta prueba el otro lado: el deposito de
// verdad, contra sello.gustitoxpress.app y la base viva.
//
// Lo que tiene que quedar claro:
//   - Sin llave no se guarda ni se baja nada.
//   - Lo guardado NO SE PUEDE MODIFICAR (el candado de la base).
//   - Repetir una linea no la duplica.
//   - Lo que se baja es identico a lo que se subio.
//   - El panel de la imprenta ve, por cliente, si su libro esta a salvo.
// Limpia todo lo que crea.
import { readFileSync } from 'node:fs';

const REF = 'szzhhlevtrcambcoytiz';
const PAT = readFileSync(new URL('../.sb_token', import.meta.url), 'utf8').trim();
const SELLO = process.env.PANEL ?? 'https://sello.gustitoxpress.app';
const RIF = 'V-22606827-5'; // RIF real distinto al del emprendimiento

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, 300));
  return JSON.parse(t);
}
const uno = async (q) => (await sql(q))[0];
const lit = (s) => `'${String(s).replace(/'/g, "''")}'`;

const limpiar = () =>
  sql(`delete from fiscal.respaldo where emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)});
       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.series where emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)});
       delete from fiscal.emisores where rif=${lit(RIF)};`);

async function puerta(llave, accion, datos = {}) {
  const r = await fetch(`${SELLO}/api/estacion`, {
    method: 'POST',
    headers: { 'content-type': 'application/json', ...(llave ? { authorization: `Bearer ${llave}` } : {}) },
    body: JSON.stringify({ accion, rif: RIF, datos }),
  });
  return { estado: r.status, cuerpo: await r.json().catch(() => ({})) };
}

// Lineas de mentira, con la pinta que tienen las de verdad (cifradas).
const linea = (seq) => ({
  seq,
  iv: 'a'.repeat(24),
  tag: 'b'.repeat(32),
  datos: Buffer.from(`asiento cifrado numero ${seq}`).toString('base64'),
});

try {
  await limpiar();
  await sql(`select fiscal.guardar_cliente(${lit(RIF)}, 'Comercial de prueba respaldo', 'Araure, Portuguesa',
             null, null, null, null, 'Estacion Fiscal', 'C', true, null);`);
  const llave = (await uno(`select fiscal.crear_llave(${lit(RIF)}, 'prueba de respaldo') as llave`)).llave;

  console.log('\n== 1. Sin llave no se guarda nada ==');
  const sinLlave = await puerta(null, 'respaldo_guardar', { lineas: [linea(1)] });
  check(sinLlave.estado === 401, `rebota (HTTP ${sinLlave.estado})`);
  const llaveMala = await puerta('gxf_' + 'f'.repeat(48), 'respaldo_guardar', { lineas: [linea(1)] });
  check(llaveMala.estado === 401, `con una llave inventada tampoco (HTTP ${llaveMala.estado} ${JSON.stringify(llaveMala.cuerpo).slice(0,60)})`);

  console.log('\n== 2. El deposito arranca vacio ==');
  const vacio = await puerta(llave, 'respaldo_hasta');
  check(vacio.estado === 200 && vacio.cuerpo.lineas === 0, `no tiene nada guardado (${vacio.cuerpo?.lineas})`);

  console.log('\n== 3. Se guardan las lineas y dice hasta donde llego ==');
  const subida = await puerta(llave, 'respaldo_guardar', { lineas: [linea(0), linea(1), linea(2), linea(3)] });
  check(subida.cuerpo.guardadas === 4, `guardo las 4 (${subida.cuerpo?.guardadas})`);
  check(subida.cuerpo.ultimo_seq === 3, `y va por el asiento 3 (${subida.cuerpo?.ultimo_seq})`);

  console.log('\n== 4. Repetir no duplica ==');
  const repetida = await puerta(llave, 'respaldo_guardar', { lineas: [linea(2), linea(3), linea(4)] });
  check(repetida.cuerpo.guardadas === 1, `de tres, solo entro la nueva (${repetida.cuerpo?.guardadas})`);
  const cuantas = await uno(
    `select count(*)::int as n from fiscal.respaldo r join fiscal.emisores e on e.id=r.emisor_id where e.rif=${lit(RIF)}`,
  );
  check(cuantas.n === 5, `en la base hay 5 lineas, ni una mas (${cuantas.n})`);

  console.log('\n== 5. Lo guardado NO se puede modificar ==');
  let problema = '';
  try {
    await sql(`update fiscal.respaldo set datos='cambiado' where seq=1
                and emisor_id in (select id from fiscal.emisores where rif=${lit(RIF)});`);
  } catch (e) {
    problema = String(e.message);
  }
  check(/solo agrega/i.test(problema), 'el candado de la base revienta cualquier UPDATE');
  const intacta = await uno(
    `select datos from fiscal.respaldo r join fiscal.emisores e on e.id=r.emisor_id
      where e.rif=${lit(RIF)} and r.seq=1`,
  );
  check(intacta.datos === linea(1).datos, 'y la linea quedo tal cual estaba');

  console.log('\n== 6. Lo que se baja es identico a lo que se subio ==');
  const bajada = await puerta(llave, 'respaldo_bajar', { desde: -1, limite: 200 });
  const lineas = bajada.cuerpo.lineas;
  check(lineas.length === 5, `bajan las 5 lineas, incluida la cabecera (${lineas.length})`);
  check(
    lineas.every((l, i) => l.seq === i && l.iv === linea(i).iv && l.tag === linea(i).tag && l.datos === linea(i).datos),
    'y vienen exactamente iguales, en orden',
  );
  const desdeDos = await puerta(llave, 'respaldo_bajar', { desde: 2, limite: 200 });
  check(desdeDos.cuerpo.lineas.length === 2, `pidiendo desde el 2 vienen solo las que faltan (${desdeDos.cuerpo.lineas.length})`);

  console.log('\n== 7. Un cliente no ve el respaldo de otro ==');
  const otroRif = 'J-50856106-6';
  const deOtro = await fetch(`${SELLO}/api/estacion`, {
    method: 'POST',
    headers: { 'content-type': 'application/json', authorization: `Bearer ${llave}` },
    body: JSON.stringify({ accion: 'respaldo_bajar', rif: otroRif, datos: { desde: -1 } }),
  });
  check(deOtro.status === 401, `con la llave de uno no se baja el respaldo de otro (HTTP ${deOtro.status})`);

  console.log('\n== 8. El panel de la imprenta lo ve ==');
  const enPanel = await uno(
    `select respaldo_lineas, respaldo_ultimo is not null as tiene_fecha
       from fiscal.clientes() where rif=${lit(RIF)}`,
  );
  check(enPanel.respaldo_lineas === 5, `la lista de clientes muestra las 5 lineas guardadas (${enPanel.respaldo_lineas})`);
  check(enPanel.tiene_fecha === true, 'y desde cuando esta a salvo');

  console.log('\n== 9. No se puede usar de deposito de cualquier cosa ==');
  const gigante = await puerta(llave, 'respaldo_guardar', {
    lineas: [{ seq: 99, iv: 'a', tag: 'b', datos: 'x'.repeat(70000) }],
  });
  check(gigante.estado >= 400, `una linea de 70 KB se rechaza (HTTP ${gigante.estado})`);
  const muchas = await puerta(llave, 'respaldo_guardar', {
    lineas: Array.from({ length: 501 }, (_, i) => linea(1000 + i)),
  });
  check(muchas.estado >= 400, `y mandar 501 de una vez tambien (HTTP ${muchas.estado})`);
} catch (e) {
  console.log('  XX  ' + String(e).slice(0, 250));
  fallos++;
} finally {
  await limpiar();
}

console.log(fallos === 0 ? '\nDEPOSITO DEL RESPALDO: TODO VERDE' : `\n${fallos} FALLO(S)`);
process.exit(fallos === 0 ? 0 : 1);
