// MESAS OLVIDADAS (2026-07-27)
// Caso real de Arepa Power: 4 mesas abiertas 48 horas (tres con consumo, una que
// nadie uso) y nadie le aviso al dueño. Ahora:
//   - la mesa que nadie uso se cierra sola (5 min si la abrio el cliente por QR,
//     30 min si la abrio el personal);
//   - la mesa CON consumo que amanece abierta se cierra marcada como PERDIDA,
//     para que la plata quede contada y no se cuele como venta buena.
// Corre contra el restaurante DEMO y LIMPIA todo.
import { createClient } from '@supabase/supabase-js';

const URL = process.env.SUPABASE_URL || process.env.VITE_SUPABASE_URL;
const ANON = process.env.SUPABASE_ANON_KEY || process.env.VITE_SUPABASE_ANON_KEY;
const SERVICE = process.env.SUPABASE_SERVICE_KEY || process.env.SUPABASE_SERVICE_ROLE_KEY;
if (!URL || !ANON || !SERVICE) {
  console.log('Faltan SUPABASE_URL / SUPABASE_ANON_KEY / SUPABASE_SERVICE_KEY');
  process.exit(1);
}

let fallos = 0;
const check = (cond, msg) => {
  console.log((cond ? '  OK  ' : '  XX  ') + msg);
  if (!cond) fallos++;
};
const anon = () => createClient(URL, ANON, { auth: { persistSession: false } });
const svc = createClient(URL, SERVICE, { auth: { persistSession: false } });

const MESAS = ['TO91', 'TO92', 'TO93', 'TO94', 'TO95', 'TO96'];
const haceMin = (m) => new Date(Date.now() - m * 60 * 1000).toISOString();

const { data: rest } = await svc.from('restaurantes').select('id').eq('slug', 'demo-gustito').maybeSingle();
const REST = rest?.id;
const { data: prods } = await svc
  .from('productos')
  .select('id,nombre,precio_usd')
  .eq('restaurante_id', REST)
  .eq('disponible', true)
  .limit(1);
const PROD = prods?.[0];
if (!REST || !PROD) {
  console.log('Demo no disponible');
  process.exit(1);
}

const limpiar = async () => {
  const { data: cuentas } = await svc.from('cuentas_mesa').select('id').eq('restaurante_id', REST).in('mesa', MESAS);
  for (const c of cuentas ?? []) {
    const { data: peds } = await svc.from('pedidos').select('id').eq('cuenta_id', c.id);
    for (const p of peds ?? []) {
      await svc.from('pedido_items').delete().eq('pedido_id', p.id);
      await svc.from('pagos').delete().eq('pedido_id', p.id);
    }
    await svc.from('pedidos').delete().eq('cuenta_id', c.id);
    await svc.from('pagos_mesa').delete().eq('cuenta_id', c.id);
    await svc.from('comensales_mesa').delete().eq('cuenta_id', c.id);
    await svc.from('cuentas_mesa').delete().eq('id', c.id);
  }
};

// Abre una mesa vacia (como cuando alguien escanea el QR y no pide nada)
const abrirVacia = async (mesa, minutos, meseroId = null) => {
  const { data, error } = await svc
    .from('cuentas_mesa')
    .insert({ restaurante_id: REST, mesa, estado: 'abierta', mesero_id: meseroId, abierta_en: haceMin(minutos) })
    .select('id')
    .single();
  if (error) throw new Error(`abrir ${mesa}: ${error.message}`);
  return data.id;
};

const pedirQr = async (mesa) => {
  const { data, error } = await anon().rpc('crear_pedido', {
    p_restaurante_id: REST,
    p_cliente_nombre: 'Cliente QR',
    p_cliente_telefono: '04120000009',
    p_tipo_entrega: 'mesa',
    p_metodo_pago: 'efectivo',
    p_items: [{ producto_id: PROD.id, nombre: PROD.nombre, precio_usd: PROD.precio_usd, cantidad: 1 }],
    p_mesa: mesa,
  });
  if (error) throw new Error(`crear_pedido(${mesa}): ${error.message}`);
  return data?.[0];
};

const estadoCuenta = async (id) => (await svc.from('cuentas_mesa').select('estado,cerrada_en').eq('id', id).maybeSingle()).data;

try {
  await limpiar();

  console.log('\n== MESA QUE NADIE USO (se cierra sola) ==');
  const viejaCliente = await abrirVacia('TO91', 6); // QR, 6 minutos
  const nuevaCliente = await abrirVacia('TO92', 2); // QR, 2 minutos
  const viejaStaff = await abrirVacia('TO93', 40, null); // personal, 40 min
  const nuevaStaff = await abrirVacia('TO94', 10, null); // personal, 10 min
  // El campo que decide es mesero_id; lo ponemos aparte para no depender de un usuario real.
  const { data: algunStaff } = await svc.from('perfiles').select('id').eq('restaurante_id', REST).limit(1);
  const STAFF = algunStaff?.[0]?.id ?? null;
  await svc.from('cuentas_mesa').update({ mesero_id: STAFF }).in('id', [viejaStaff, nuevaStaff]);

  const r1 = await svc.rpc('fn_cerrar_mesas_vacias');
  check(!r1.error, `la funcion corre: ${r1.error?.message ?? 'ok'}`);
  check((await estadoCuenta(viejaCliente))?.estado === 'cerrada', 'QR con 6 min sin pedir: se cierra sola');
  check((await estadoCuenta(nuevaCliente))?.estado === 'abierta', 'QR con 2 min: sigue abierta (todavia esta viendo el menu)');
  if (STAFF) {
    check((await estadoCuenta(viejaStaff))?.estado === 'cerrada', 'mesera con 40 min sin cargar nada: se cierra');
    check((await estadoCuenta(nuevaStaff))?.estado === 'abierta', 'mesera con 10 min: sigue abierta (le damos 30)');
  }

  console.log('\n== MESA CON COMIDA: la de vacias NO la toca ==');
  const conComida = await pedirQr('TO95');
  await svc.from('cuentas_mesa').update({ abierta_en: haceMin(600) }).eq('id', conComida.cuenta_id);
  await svc.rpc('fn_cerrar_mesas_vacias');
  check((await estadoCuenta(conComida.cuenta_id))?.estado === 'abierta', 'mesa con consumo NO se cierra por vacia, asi lleve 10 horas');

  console.log('\n== MESA CON COMIDA QUE AMANECIO ABIERTA (perdida) ==');
  const reciente = await pedirQr('TO96');
  await svc.from('cuentas_mesa').update({ abierta_en: haceMin(120) }).eq('id', reciente.cuenta_id); // 2 horas
  const r2 = await svc.rpc('fn_cerrar_mesas_olvidadas');
  check(!r2.error, `la funcion de madrugada corre: ${r2.error?.message ?? 'ok'}`);
  check((await estadoCuenta(reciente.cuenta_id))?.estado === 'abierta', 'mesa de hace 2 horas: NO se toca (el negocio esta abierto)');
  check((await estadoCuenta(conComida.cuenta_id))?.estado === 'cerrada', 'mesa de hace 10 horas: se cierra sola');

  const { data: perdida } = await svc
    .from('pagos_mesa')
    .select('metodo,monto_usd,nota,mesero_nombre,verificado')
    .eq('cuenta_id', conComida.cuenta_id);
  check(perdida?.length === 1, `queda UN registro del cierre (hay ${perdida?.length ?? 0})`);
  check(perdida?.[0]?.metodo === 'perdida', `anotado como PERDIDA, no como venta (fue "${perdida?.[0]?.metodo}")`);
  check(Number(perdida?.[0]?.monto_usd) === Number(PROD.precio_usd), `por el monto real sin cobrar (${perdida?.[0]?.monto_usd} vs ${PROD.precio_usd})`);
  check(/nadie la cobro/i.test(perdida?.[0]?.nota ?? ''), 'con el motivo escrito, para que el dueño sepa que paso');
  const { data: pedCerrado } = await svc.from('pedidos').select('pago_mesa_id').eq('id', conComida.pedido_id).maybeSingle();
  check(!!pedCerrado?.pago_mesa_id, 'el pedido queda amarrado a ese registro (no vuelve a contarse)');

  console.log('\n== EL CLIENTE NO PIERDE NADA: pide y la mesa se le abre otra vez ==');
  const otraVez = await pedirQr('TO91'); // la que se habia cerrado por vacia
  check(!!otraVez?.cuenta_id && otraVez.cuenta_id !== viejaCliente, 'tras cerrarse sola, al pedir se abre una cuenta nueva');
  const est = await svc.from('pedidos').select('estado').eq('id', otraVez.pedido_id).maybeSingle();
  check(est.data?.estado === 'confirmado', 'y ese pedido va derecho a la cocina');
} catch (e) {
  console.log('  XX  ' + e.message);
  fallos++;
} finally {
  await limpiar();
}

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