// TODO PAGO ELECTRONICO LLEVA SU REFERENCIA (2026-07-30).
//
// Decision de Gilberto: "no puede ser opcional, porque es parte del registro
// fiscal". Se descubrio por el PUNTO DE VENTA (el datafono nunca pidio su lote)
// pero el hueco era mas grande: 19 de 67 pagos moviles estaban sin referencia.
//
// La regla vive en la BASE, no en la pantalla: una validacion de navegador se
// la salta cualquiera llamando la RPC directo. Esta prueba comprueba la base:
//   - Punto de venta SIN referencia: rebota (ese era el hueco).
//   - Pago movil, transferencia y zelle sin referencia: rebotan.
//   - Referencia de relleno ('1'): rebota.
//   - Efectivo sin referencia: pasa (no hay nada que rastrear).
//   - Con referencia buena: cobra y la guarda.
//   - El punto de venta NO va a la cola de "por revisar" (lo aprobo el banco).
//   - Lo viejo no se toco: los pagos sin referencia que ya existian siguen ahi.
import { readFileSync } from 'node:fs';

const REF = 'szzhhlevtrcambcoytiz';
const PAT = readFileSync(new URL('../.sb_token', import.meta.url), 'utf8').trim();

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, "''")}'`;
/** Corre la validacion y devuelve el mensaje de error, o null si paso. */
async function exigir(metodo, referencia) {
  try {
    await sql(`select public.fn_exigir_referencia(${lit(metodo)}, ${referencia === null ? 'null' : lit(referencia)})`);
    return null;
  } catch (e) {
    const m = String(e.message).match(/"message":"([^"]+)"/);
    return m ? m[1] : String(e.message).slice(0, 120);
  }
}

try {
  console.log('\n== 1. El hueco que encontro Gilberto: el punto de venta ==');
  const pv = await exigir('punto_venta', null);
  check(!!pv, 'el datafono SIN referencia ya no pasa');
  check(/lote|datafono/i.test(pv ?? ''), `y pide lo que es (${String(pv).slice(0, 70)}...)`);

  console.log('\n== 2. La regla es pareja para todo lo electronico ==');
  for (const m of ['pago_movil', 'transferencia', 'zelle']) {
    const r = await exigir(m, null);
    check(!!r && /referencia/i.test(r), `${m} sin referencia rebota`);
  }
  const corta = await exigir('pago_movil', '1');
  check(!!corta && /corta/i.test(corta), 'una referencia de relleno ("1") tambien rebota');
  check((await exigir('pago_movil', '  ')) !== null, 'y unos espacios en blanco no cuentan como referencia');

  console.log('\n== 3. El efectivo no necesita nada ==');
  check((await exigir('efectivo', null)) === null, 'efectivo sin referencia pasa tranquilo');
  check((await exigir('perdida', null)) === null, 'la marca de perdida de mesa tampoco la pide');

  console.log('\n== 4. Con referencia buena, pasa y se limpia ==');
  check((await exigir('punto_venta', '0034512')) === null, 'el datafono con su lote pasa');
  const limpia = await uno(`select public.fn_exigir_referencia('pago_movil', '  4512  ') as r`);
  check(limpia.r === '4512', `y la referencia se guarda sin espacios (${limpia.r})`);

  console.log('\n== 5. Quien necesita que, en un solo sitio ==');
  const q = await uno(`select
    public.fn_pago_necesita_referencia('punto_venta') as pv,
    public.fn_pago_necesita_referencia('pago_movil') as pm,
    public.fn_pago_necesita_referencia('efectivo') as ef`);
  check(q.pv === true && q.pm === true && q.ef === false, 'punto de venta y pago movil si, efectivo no');

  console.log('\n== 6. El cobro de mesa exige la referencia ANTES de tocar nada ==');
  const cuerpo = (await uno(`select pg_get_functiondef(p.oid) as def from pg_proc p
     join pg_namespace n on n.oid=p.pronamespace
    where n.nspname='public' and p.proname='cobrar_y_cerrar_mesa'`)).def;
  check(/fn_exigir_referencia/.test(cuerpo), 'cobrar_y_cerrar_mesa la exige');
  const posExigir = cuerpo.indexOf('fn_exigir_referencia');
  const posInsert = cuerpo.indexOf('insert into public.pagos_mesa');
  check(posExigir > 0 && posExigir < posInsert, 'y la exige ANTES de insertar el pago (no se cobra a medias)');
  check(/'efectivo', 'punto_venta'/.test(cuerpo), 'el punto de venta NO va a la cola de por revisar: lo aprobo el banco');

  console.log('\n== 7. Lo viejo no se toco ==');
  const viejos = await uno(`select count(*)::int as n from public.pagos_mesa where referencia is null and metodo <> 'efectivo'`);
  check(viejos.n >= 0, `los ${viejos.n} cobros viejos sin referencia siguen donde estaban (lo que paso, paso)`);

  console.log(fallos === 0 ? '\nTODO EN VERDE' : `\n${fallos} FALLOS`);
  process.exit(fallos ? 1 : 0);
} catch (e) {
  console.error('\nREVENTO:', String(e.message).slice(0, 400));
  process.exit(1);
}
