// LA FACTURA LLEGA AL TELEFONO (2026-07-29)
//
// Prueba de la RPC publica factura_de_venta: el cliente, con el uuid de SU
// pedido (el mismo secreto de pedido_seguimiento), ve numero/control/token de
// su documento sellado. Lo que NO debe pasar: ver ventas sin sellar, ver nada
// con un uuid ajeno inventado, o que un tipo invalido reviente feo.
//
// Siembra un emisor y filas de cola de PRUEBA con service/Management API y las
// limpia al final. No toca ningun emisor real.
import { readFileSync } from 'node:fs';
import { randomUUID } from 'node:crypto';

const REF = 'szzhhlevtrcambcoytiz';
const PAT = readFileSync(new URL('../.sb_token', import.meta.url), 'utf8').trim();
const URL_SB = `https://${REF}.supabase.co`;

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, "''")}'`;

// La anon key, al vuelo (no vive en el repo).
async function anonKey() {
  const r = await fetch(`https://api.supabase.com/v1/projects/${REF}/api-keys?reveal=true`, {
    headers: { Authorization: `Bearer ${PAT}` },
  });
  const ks = await r.json();
  return ks.find((k) => k.name === 'anon').api_key;
}

// La RPC exactamente como la llama el telefono del cliente: PostgREST + anon.
async function rpcAnon(anon, tipo, origenId) {
  const r = await fetch(`${URL_SB}/rest/v1/rpc/factura_de_venta`, {
    method: 'POST',
    headers: { apikey: anon, Authorization: `Bearer ${anon}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ p_tipo: tipo, p_origen_id: origenId }),
  });
  return { status: r.status, cuerpo: await r.json().catch(() => null) };
}

const RIF = 'V-22606827-5'; // RIF de prueba de la casa (test_carga_estaciones)
const selladoId = randomUUID();
const pendienteId = randomUUID();
const TOKEN = 'tok_prueba_factura_' + randomUUID().slice(0, 8);
let emisorId = null;

async function limpiar() {
  if (!emisorId) return;
  await sql(`delete from fiscal.cola_gustito where emisor_id = ${lit(emisorId)}::uuid;
             delete from fiscal.llaves where emisor_id = ${lit(emisorId)}::uuid;
             delete from fiscal.estaciones where emisor_id = ${lit(emisorId)}::uuid;
             delete from fiscal.emisores where id = ${lit(emisorId)}::uuid;`);
}

try {
  const anon = await anonKey();

  // --- siembra -------------------------------------------------------------
  const yaExiste = await uno(`select id from fiscal.emisores where rif = ${lit(RIF)}`);
  if (yaExiste) {
    // huerfano de otra corrida: fuera, para arrancar limpio
    await sql(`delete from fiscal.cola_gustito where emisor_id = ${lit(yaExiste.id)}::uuid;
               delete from fiscal.llaves where emisor_id = ${lit(yaExiste.id)}::uuid;
               delete from fiscal.estaciones where emisor_id = ${lit(yaExiste.id)}::uuid;
               delete from fiscal.emisores where id = ${lit(yaExiste.id)}::uuid;`);
  }
  const demo = await uno(
    `select id from public.restaurantes where nombre ilike '%demo%' order by creado_en limit 1`,
  );
  check(!!demo, 'hay restaurante demo para colgar la prueba');

  emisorId = (
    await uno(`insert into fiscal.emisores (rif, razon_social, domicilio_fiscal, llave_hash, rif_comprobado)
               values (${lit(RIF)}, 'Prueba Factura Telefono', 'Acarigua', 'x', true) returning id`)
  ).id;

  await sql(`insert into fiscal.cola_gustito
      (restaurante_id, emisor_id, tipo, origen_id, estado, sellado_en, numero_documento, numero_control, token)
    values
      (${lit(demo.id)}::uuid, ${lit(emisorId)}::uuid, 'pedido', ${lit(selladoId)}::uuid,
       'sellado', now(), 123, 987654, ${lit(TOKEN)}),
      (${lit(demo.id)}::uuid, ${lit(emisorId)}::uuid, 'pedido', ${lit(pendienteId)}::uuid,
       'pendiente', null, null, null, null)`);

  // --- lo que SI debe pasar --------------------------------------------------
  const ok = await rpcAnon(anon, 'pedido', selladoId);
  check(ok.status === 200, `la RPC responde 200 al anonimo (${ok.status})`);
  check(ok.cuerpo?.numero_documento === 123, 'trae el numero de documento');
  check(ok.cuerpo?.numero_control === 987654, 'trae el numero de control');
  check(ok.cuerpo?.token === TOKEN, 'trae el token del sello');
  check(ok.cuerpo?.rif === RIF && ok.cuerpo?.razon_social === 'Prueba Factura Telefono', 'dice quien emite');
  check(!('venta' in (ok.cuerpo ?? {})) && !('renglones' in (ok.cuerpo ?? {})), 'NO trae renglones ni la venta cruda');

  // --- lo que NO debe pasar --------------------------------------------------
  const sinSellar = await rpcAnon(anon, 'pedido', pendienteId);
  check(sinSellar.cuerpo === null, 'una venta sin sellar devuelve vacio (no hay documento que mostrar)');

  const ajena = await rpcAnon(anon, 'pedido', randomUUID());
  check(ajena.cuerpo === null, 'un uuid inventado devuelve vacio');

  const tipoMalo = await rpcAnon(anon, 'cualquiercosa', selladoId);
  check(tipoMalo.status === 200 && tipoMalo.cuerpo === null, 'un tipo invalido devuelve vacio, sin reventar');

  const comoCuenta = await rpcAnon(anon, 'cuenta', selladoId);
  check(comoCuenta.cuerpo === null, 'el mismo uuid preguntado como cuenta no cruza (tipo estricto)');
} finally {
  await limpiar();
  console.log('\nLimpieza hecha (emisor y cola de prueba fuera)');
}

console.log(fallos === 0 ? '\nFACTURA AL TELEFONO OK' : `\n${fallos} FALLOS`);
process.exit(fallos === 0 ? 0 : 1);
