// Verificacion de CUENTAS SEPARADAS (fase 1) contra la BD viva (nube).
// Usa el restaurante DEMO con mesas de prueba T92/T93, un mesero temporal,
// y LIMPIA todo al final. Env: SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_KEY.
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;
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 nuevo = () => createClient(URL, ANON, { auth: { persistSession: false } });
const svc = createClient(URL, SERVICE, { auth: { persistSession: false } });
const num = (x) => Math.round(Number(x) * 100) / 100;

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

const EMAIL = 'mesero.test.partes@gustitoxpress.app';
const CLAVE = 'MeseroTest2026!';
let joseId;
const limpiar = async () => {
  for (const mesa of ['T92', 'T93']) {
    const { data: ctas } = await svc.from('cuentas_mesa').select('id').eq('restaurante_id', REST).eq('mesa', mesa);
    for (const c of ctas ?? []) {
      await svc.from('pedidos').delete().eq('cuenta_id', c.id);
      await svc.from('cuentas_mesa').delete().eq('id', c.id); // pagos_mesa cae en cascada
    }
  }
  if (joseId) await svc.auth.admin.deleteUser(joseId).catch(() => {});
};

try {
  await limpiar(); // por si quedo basura de una corrida anterior
  const { data: u, error: eU } = await svc.auth.admin.createUser({ email: EMAIL, password: CLAVE, email_confirm: true });
  if (eU) throw new Error('createUser: ' + eU.message);
  joseId = u.user.id;
  await svc.from('perfiles').upsert({ id: joseId, rol: 'staff', restaurante_id: REST, nombre: 'José Partes' });
  console.log('Setup listo\n');

  const jose = nuevo();
  await jose.auth.signInWithPassword({ email: EMAIL, password: CLAVE });
  const anon = nuevo();

  const pedir = async (cli, nombre, cant, mesa) => {
    const { data, error } = await cli.rpc('crear_pedido', {
      p_restaurante_id: REST, p_cliente_nombre: nombre, p_cliente_telefono: '',
      p_tipo_entrega: 'mesa', p_metodo_pago: 'efectivo',
      p_items: [{ producto_id: PROD_ID, cantidad: cant, _c: nombre + mesa }], p_mesa: mesa,
    });
    if (error) throw new Error('crear_pedido ' + nombre + ': ' + error.message);
    return data[0];
  };

  // Mesa T92: Pedro (mesero), Ana (mesero), Luis (QR anon)
  const rPedro = await pedir(jose, 'Pedro', 1, 'T92');
  const rAna = await pedir(jose, 'Ana', 2, 'T92');
  const rLuis = await pedir(anon, 'Luis', 1, 'T92');
  const CTA = rPedro.cuenta_id;
  check(rAna.cuenta_id === CTA && rLuis.cuenta_id === CTA, 'Los 3 pedidos caen en la misma cuenta de T92');

  const { data: peds } = await svc.from('pedidos').select('id,total_usd,cliente_nombre').eq('cuenta_id', CTA);
  const total = num(peds.reduce((s, p) => s + Number(p.total_usd), 0));
  const pPedro = peds.find((p) => p.cliente_nombre === 'Pedro');
  const pAna = peds.find((p) => p.cliente_nombre === 'Ana');
  const pLuis = peds.find((p) => p.cliente_nombre === 'Luis');

  // 1) Cobrar la parte de Pedro
  const { data: c1, error: e1 } = await jose.rpc('cobrar_parte_mesa', {
    p_cuenta_id: CTA, p_pedido_ids: [pPedro.id], p_metodo: 'efectivo', p_nota: 'Pedro',
  });
  check(!e1, 'Mesero cobra la parte de Pedro' + (e1 ? ' -> ' + e1.message : ''));
  check(num(c1?.[0]?.monto_usd) === num(pPedro.total_usd), 'Monto cobrado = consumo de Pedro');
  check(num(c1?.[0]?.saldo_usd) === num(total - Number(pPedro.total_usd)), 'Saldo restante correcto');
  const { data: pedroDespues } = await svc.from('pedidos').select('pago_mesa_id').eq('id', pPedro.id).maybeSingle();
  check(!!pedroDespues?.pago_mesa_id, 'El pedido de Pedro quedo amarrado a su cobro');
  const { data: pago1 } = await svc.from('pagos_mesa').select('mesero_nombre,monto_usd').eq('cuenta_id', CTA).maybeSingle();
  check(pago1?.mesero_nombre === 'José Partes', 'El cobro quedo firmado por quien cobro');

  // 2) DOBLE COBRO: volver a cobrar el pedido de Pedro -> rechazado
  const { error: eDup } = await jose.rpc('cobrar_parte_mesa', {
    p_cuenta_id: CTA, p_pedido_ids: [pPedro.id], p_metodo: 'efectivo',
  });
  check(!!eDup, 'Doble cobro RECHAZADO (' + (eDup?.message ?? 'sin error!') + ')');

  // 3) Pedido de OTRA cuenta (T93) -> rechazado y nada se cobra
  const rOtra = await pedir(anon, 'Mario', 1, 'T93');
  const { error: eOtra } = await jose.rpc('cobrar_parte_mesa', {
    p_cuenta_id: CTA, p_pedido_ids: [pAna.id, rOtra.pedido_id], p_metodo: 'efectivo',
  });
  check(!!eOtra, 'Cobrar pedido de OTRA mesa RECHAZADO (todo o nada)');
  const { data: anaIntacta } = await svc.from('pedidos').select('pago_mesa_id').eq('id', pAna.id).maybeSingle();
  check(anaIntacta?.pago_mesa_id === null, 'El pedido de Ana NO quedo cobrado por el intento fallido');

  // 4) Anon NO puede cobrar
  const { error: eAnon } = await anon.rpc('cobrar_parte_mesa', {
    p_cuenta_id: CTA, p_pedido_ids: [pAna.id], p_metodo: 'efectivo',
  });
  check(!!eAnon, 'Un cliente anonimo NO puede cobrar (' + (eAnon?.message ?? 'sin error!') + ')');

  // 5) Cancelados fuera: se cancela el pedido de Luis y los totales lo excluyen
  await svc.from('pedidos').update({ estado: 'cancelado' }).eq('id', pLuis.id);
  const { data: act } = await anon.rpc('cuenta_mesa_activa', { p_restaurante_id: REST, p_mesa: 'T92' });
  check(num(act?.[0]?.total_usd) === num(total - Number(pLuis.total_usd)), 'Total de la cuenta EXCLUYE el pedido cancelado');
  const { error: eCanc } = await jose.rpc('cobrar_parte_mesa', {
    p_cuenta_id: CTA, p_pedido_ids: [pLuis.id], p_metodo: 'efectivo',
  });
  check(!!eCanc, 'Cobrar un pedido cancelado RECHAZADO');

  // 6) Panel y cliente ven el estado de pago
  const { data: mcm } = await jose.rpc('mis_cuentas_mesa', { p_restaurante_id: REST });
  const fila = (mcm ?? []).find((c) => c.mesa === 'T92');
  check(num(fila?.pagado_usd) === num(pPedro.total_usd), 'mis_cuentas_mesa reporta lo pagado');
  const { data: cm } = await anon.rpc('cuenta_mesa', { p_cuenta_id: CTA });
  const js = cm?.[0]?.pedidos ?? [];
  const jsPedro = js.find((p) => p.cliente === 'Pedro');
  const jsAna = js.find((p) => p.cliente === 'Ana');
  check(jsPedro?.pagado === true && jsAna?.pagado === false, 'El cliente ve quien pago y quien no');

  // 7) El mesero NO anula cobros (eso es del dueño)
  const { data: delStaff } = await jose.from('pagos_mesa').delete().eq('cuenta_id', CTA).select();
  check((delStaff?.length ?? 0) === 0, 'Mesero NO puede anular un cobro (RLS)');

  // 8) Cobrar el resto y liberar sigue funcionando
  const { error: eCierre } = await jose.rpc('cerrar_cuenta_mesa', { p_cuenta_id: CTA });
  check(!eCierre, 'Cobrar el resto y liberar la mesa funciona' + (eCierre ? ' -> ' + eCierre.message : ''));
  const { data: ctaFin } = await svc.from('cuentas_mesa').select('estado').eq('id', CTA).maybeSingle();
  check(ctaFin?.estado === 'cerrada', 'La cuenta quedo cerrada');
} catch (e) {
  console.log('  XX  Excepción: ' + e.message);
  fallos++;
} finally {
  await limpiar();
  console.log('\nLimpieza hecha (pedidos, cuentas, cobros y usuario de prueba fuera)');
}

console.log(fallos === 0 ? '\nCUENTAS SEPARADAS OK' : `\nCUENTAS SEPARADAS: ${fallos} FALLO(S)`);
process.exit(fallos === 0 ? 0 : 1);
