// Prueba VIVA del blindaje de la cola fiscal.
//
// Lo que paso de verdad (2026-07-31): la Estacion halaba una venta, la sellaba
// en su libro y al confirmarle a la nube reventaba. Como la venta seguia
// 'pendiente', la nube se la volvia a entregar en la ronda siguiente: sello la
// misma venta cada 10 segundos durante 20 minutos, sin nadie trabajando. Con
// volumen, una sola venta trabada le come el turno a los demas negocios.
//
// Aca se reproduce el escenario: se pide la venta muchas veces SIN confirmarla
// nunca, y se comprueba que la nube deja de entregarla enseguida.
//
// Correr: node scripts/test_cola_no_martilla.mjs
import fs from 'node:fs';

const REF = process.env.SB_REF ?? 'szzhhlevtrcambcoytiz';
const PAT = (process.env.SB_TOKEN ?? fs.readFileSync(new URL('../.sb_token', import.meta.url), 'utf8')).trim();
const sql = async (q) => {
  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: q }),
  });
  const t = await r.text();
  if (!r.ok) throw new Error(t.slice(0, 300));
  return JSON.parse(t);
};

let ok = 0, mal = 0;
const check = (t, cond, extra = '') => { if (cond) { ok++; console.log('  ok  ' + t); } else { mal++; console.log('  MAL ' + t + (extra ? ' -> ' + extra : '')); } };

// Emisor y llave de prueba (RIF de pruebas, nunca uno real).
const RIF = 'V-22606827-5';
const [{ existe }] = await sql(`select count(1) existe from fiscal.emisores where rif = '${RIF}'`);
if (!Number(existe)) {
  await sql(`select fiscal.guardar_cliente('${RIF}', 'Emisor de prueba cola', 'B', 'Prueba', null, null, null, null, 'prueba', true, null)`);
}
const [{ id: emisor }] = await sql(`select id from fiscal.emisores where rif = '${RIF}'`);
const [{ llave }] = await sql(`select fiscal.crear_llave('${RIF}', 'prueba cola') llave`);

// Un restaurante cualquiera para poder insertar en la cola (solo llena la FK).
const [{ id: rest }] = await sql(`select id from public.restaurantes order by creado_en limit 1`);
const [{ id: cola }] = await sql(`insert into fiscal.cola_gustito (restaurante_id, emisor_id, tipo, origen_id, estado)
  values ('${rest}', '${emisor}', 'pedido', gen_random_uuid(), 'pendiente') returning id`);

console.log('\n== la nube entrega la venta, pero no una y otra vez ==');
// Cuenta solo ESTA venta: el emisor de pruebas puede tener otras de corridas
// anteriores y lo que se mide aca es cuantas veces vuelve a salir la misma.
const pedir = async () => {
  const [{ v }] = await sql(`select fiscal.ventas_pendientes('${llave}', '${RIF}', 50) v`);
  return (Array.isArray(v) ? v : []).filter((x) => x.cola_id === cola).length;
};

const primera = await pedir();
check('la primera vuelta si la entrega', primera === 1, `entrego ${primera}`);

let entregasSeguidas = 0;
for (let i = 0; i < 12; i++) entregasSeguidas += await pedir();
check('las 12 vueltas siguientes NO la entregan otra vez', entregasSeguidas === 0, `la entrego ${entregasSeguidas} veces mas`);

const [fila] = await sql(`select intentos, estado, proximo_intento_en > now() as esperando from fiscal.cola_gustito where id = '${cola}'`);
check('quedo contado el intento', Number(fila.intentos) === 1, `intentos=${fila.intentos}`);
check('y con una espera programada antes del proximo', fila.esperando === true);

console.log('\n== cuando la espera vence, vuelve a intentarlo sola ==');
await sql(`update fiscal.cola_gustito set proximo_intento_en = now() - interval '1 second' where id = '${cola}'`);
check('la vuelve a entregar al vencer la espera', (await pedir()) === 1);

console.log('\n== a fuerza de fallar, se aparta para revision ==');
for (let i = 0; i < 12; i++) {
  await sql(`update fiscal.cola_gustito set proximo_intento_en = now() - interval '1 second' where id = '${cola}' and estado='pendiente'`);
  await pedir();
}
const [fin] = await sql(`select intentos, estado, ultimo_error from fiscal.cola_gustito where id = '${cola}'`);
check('deja de entregarse y queda apartada', fin.estado === 'error', `estado=${fin.estado}`);
check('con el motivo escrito, para que se vea en el panel', /sin que la Estacion confirmara/.test(fin.ultimo_error ?? ''), fin.ultimo_error);
const [revisar] = await sql(`select count(1) n from fiscal.cola_por_revisar() where origen_id = (select origen_id from fiscal.cola_gustito where id='${cola}')`);
check('y sale en la lista de ventas por revisar del panel', Number(revisar.n) === 1);

console.log('\n== el latido no le pide trabajo a la Estacion si no hay nada listo ==');
const [{ v: latido }] = await sql(`select fiscal.latido('${llave}', '${RIF}', '{"equipo":"prueba-cola"}'::jsonb) v`);
check('el latido reporta 0 pendientes entregables', latido.pendientes_en_nube === 0, JSON.stringify(latido));
check('y le manda descansar, no volver enseguida', latido.volver_en_segundos >= 60, `volver_en_segundos=${latido.volver_en_segundos}`);

// limpieza
await sql(`delete from fiscal.cola_gustito where id = '${cola}'`);
await sql(`delete from fiscal.estaciones where emisor_id = '${emisor}' and equipo = 'prueba-cola'`);
await sql(`delete from fiscal.llaves where emisor_id = '${emisor}' and nombre = 'prueba cola'`);

console.log(`\n${ok} bien, ${mal} mal`);
process.exitCode = mal ? 1 : 0;
