// Prueba VIVA: toda accion que pide el panel de la imprenta existe en el
// despachador de la base.
//
// Esta clase de bug ya se cobro dos pantallas en produccion: la del Reporte del
// SENIAT (pedia 'relacion_mensual', el despachador conocia 'relacion') y la de
// Negocios Gustito (pedia 'negocios_gustito', conocia 'negocios'). En los dos
// casos la pantalla se veia vacia, sin decir que estaba rota. Como el nombre de
// la accion es un texto suelto entre el navegador y la base, nada los ata: esta
// prueba es esa atadura.
//
// Correr: node scripts/test_acciones_panel.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 q = async (sql) => {
  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: sql }),
  });
  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 : '')); } };

// 1. lo que pide la pantalla (la del repo, que es la fuente)
const html = fs.readFileSync(new URL('../apps/validador/public/admin.html', import.meta.url), 'utf8');
const pide = [...new Set([...html.matchAll(/api\(\s*['"]([a-z_0-9]+)['"]/gi)].map((m) => m[1]))].sort();

// 2. lo que atiende la Pages Function sin bajar a la base
const fn = fs.readFileSync(new URL('../apps/validador/functions/api/admin.ts', import.meta.url), 'utf8');
const enLaPuerta = [...new Set([...fn.matchAll(/accion\s*===\s*['"]([a-z_0-9]+)['"]/gi)].map((m) => m[1]))];

// 3. lo que acepta el despachador VIVO
const filas = await q(`select pg_get_functiondef(p.oid) d from pg_proc p
  join pg_namespace n on n.oid=p.pronamespace
 where p.proname='fn_panel_imprenta' and n.nspname in ('fiscal','public')`);
if (!filas.length) throw new Error('no encontre fn_panel_imprenta en la base viva');
const cuerpo = filas[0].d;
const acepta = new Set();
for (const m of cuerpo.matchAll(/when\s+((?:'[a-z_0-9]+'\s*,?\s*)+)then/gi)) {
  for (const n of m[1].matchAll(/'([a-z_0-9]+)'/g)) acepta.add(n[1]);
}

console.log(`\nla pantalla pide ${pide.length} acciones; el despachador acepta ${acepta.size}\n`);
const huerfanas = pide.filter((a) => !acepta.has(a) && !enLaPuerta.includes(a));
check('ninguna accion de la pantalla le falta al despachador', huerfanas.length === 0, huerfanas.join(', '));

// las pantallas que ya se rompieron por esto, una por una
for (const a of ['negocios_gustito', 'relacion_mensual', 'resumen_mensual', 'estaciones', 'cola']) {
  check(`el despachador reconoce "${a}"`, acepta.has(a));
}

// Un solo nombre por accion: un despachador que acepta nombres que nadie pide
// es como esconder el desajuste debajo de la alfombra, que es exactamente lo
// que dejo pasar los dos bugs anteriores.
const deMas = [...acepta].filter((a) => !pide.includes(a) && !enLaPuerta.includes(a));
check('el despachador no acepta nombres que nadie usa', deMas.length === 0, deMas.join(', '));

// 4. lo desplegado tiene que ser lo mismo que el repo
try {
  const vivo = await (await fetch('https://sello.gustitoxpress.app/admin')).text();
  const pideVivo = [...new Set([...vivo.matchAll(/api\(\s*['"]([a-z_0-9]+)['"]/gi)].map((m) => m[1]))];
  const faltanVivo = pideVivo.filter((a) => !acepta.has(a) && !enLaPuerta.includes(a));
  check('el panel DESPLEGADO tampoco pide acciones que no existen', faltanVivo.length === 0, faltanVivo.join(', '));
} catch (e) {
  console.log('  (no se pudo revisar el panel desplegado: ' + String(e).slice(0, 80) + ')');
}

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