// Verificacion de RESERVA "voy a comer aqui" -> se convierte en mesa real.
// Usa el restaurante DEMO, mesa TR90, un staff temporal, y LIMPIA todo.
// 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 MESA = 'TR90';

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').eq('restaurante_id', REST).eq('disponible', true).limit(1);
const PROD_ID = prods?.[0]?.id;
if (!PROD_ID) {
  console.log('Demo sin productos disponibles');
  process.exit(1);
}

const EMAIL = 'staff.test.reserva@gustitoxpress.app';
const CLAVE = 'ReservaTest2026!';
let staffUid;
let otroRestUid; // staff de OTRO restaurante, para probar que no puede sentar esta reserva
let pedidoId;
let cuentaId;

const limpiar = async () => {
  for (const mesa of [MESA]) {
    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').update({ cuenta_id: null }).eq('cuenta_id', c.id);
      await svc.from('cuentas_mesa').delete().eq('id', c.id); // comensales_mesa cae en cascada
    }
  }
  if (pedidoId) await svc.from('pedidos').delete().eq('id', pedidoId);
  if (staffUid) await svc.auth.admin.deleteUser(staffUid).catch(() => {});
  if (otroRestUid) await svc.auth.admin.deleteUser(otroRestUid).catch(() => {});
};

try {
  await limpiar();

  // Setup: staff DE ESTE restaurante (quien sienta la reserva) y staff de OTRO
  // restaurante real (para probar el candado de permisos).
  const { data: u1, error: e1 } = await svc.auth.admin.createUser({ email: EMAIL, password: CLAVE, email_confirm: true });
  if (e1) throw new Error('createUser staff: ' + e1.message);
  staffUid = u1.user.id;
  await svc.from('perfiles').upsert({ id: staffUid, rol: 'staff', restaurante_id: REST, nombre: 'Staff Reserva Test' });

  const { data: otroRest } = await svc.from('restaurantes').select('id').neq('id', REST).limit(1).maybeSingle();
  const EMAIL2 = 'staff.test.reserva.otro@gustitoxpress.app';
  const { data: u2, error: e2 } = await svc.auth.admin.createUser({ email: EMAIL2, password: CLAVE, email_confirm: true });
  if (e2) throw new Error('createUser otro staff: ' + e2.message);
  otroRestUid = u2.user.id;
  await svc.from('perfiles').upsert({ id: otroRestUid, rol: 'staff', restaurante_id: otroRest.id, nombre: 'Staff Otro Restaurante' });

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

  // 1) El cliente pide remoto, tipo 'reserva', para 4 personas.
  const { data: creado, error: eCrear } = await anon.rpc('crear_pedido', {
    p_restaurante_id: REST,
    p_cliente_nombre: 'Cliente Reserva Test',
    p_cliente_telefono: '04120001111',
    p_tipo_entrega: 'reserva',
    p_metodo_pago: 'efectivo',
    p_items: [{ producto_id: PROD_ID, cantidad: 1 }],
    p_personas: 4,
  });
  check(!eCrear && !!creado?.[0]?.pedido_id, 'crear_pedido con tipo_entrega=reserva funciona' + (eCrear ? ' -> ' + eCrear.message : ''));
  pedidoId = creado?.[0]?.pedido_id;

  const { data: pedFila } = await svc.from('pedidos').select('*').eq('id', pedidoId).maybeSingle();
  check(pedFila?.tipo_entrega === 'reserva', 'el pedido queda con tipo_entrega=reserva');
  check(pedFila?.estado === 'recibido', 'arranca en estado recibido, igual que pickup (cocina lo acepta normal)');
  check(pedFila?.personas === 4, 'guarda personas=4');
  check(pedFila?.cuenta_id === null, 'NO crea cuenta_mesa todavia (nadie fisico en el local aun)');
  check(pedFila?.mesa === null, 'sin mesa asignada todavia');

  // El arreglo de fondo: una reserva NO debe generar cobro individual (`pagos`).
  // Si lo hiciera, el cliente podria pagar por adelantado Y la cuenta de mesa le
  // cobraria el mismo total otra vez al cerrar (doble cobro real, detectado por Gilberto).
  const { data: pagosDelPedido } = await svc.from('pagos').select('id').eq('pedido_id', pedidoId);
  check((pagosDelPedido ?? []).length === 0, 'una reserva NO genera fila en pagos (se paga junto en la mesa, no por adelantado)');

  // pedido_seguimiento (lo que ve el cliente en /pedido/:id) trae mesa/cuenta_id/
  // personas: antes de sentarse, sin mesa ni cuenta todavia.
  const { data: segAntes } = await anon.rpc('pedido_seguimiento', { p_pedido_id: pedidoId });
  const segAntesFila = segAntes?.[0];
  check(segAntesFila?.personas === 4 && segAntesFila?.mesa === null && segAntesFila?.cuenta_id === null,
    'pedido_seguimiento antes de sentarse: personas=4, sin mesa ni cuenta');

  // 2) Un desconocido (anon) no puede sentar la reserva.
  const { error: eAnonSienta } = await anon.rpc('sentar_reserva', { p_pedido_id: pedidoId, p_mesa: MESA });
  check(!!eAnonSienta, 'un anonimo NO puede sentar la reserva' + (eAnonSienta ? '' : ' -> FALLO: no dio error'));

  // 3) El staff de OTRO restaurante tampoco puede.
  const { error: eOtroSienta } = await staffOtro.rpc('sentar_reserva', { p_pedido_id: pedidoId, p_mesa: MESA });
  check(!!eOtroSienta, 'el staff de OTRO restaurante NO puede sentar esta reserva' + (eOtroSienta ? '' : ' -> FALLO: no dio error'));

  // 4) El mesero ESCANEA EL TICKET QR del cliente (mismo camino de codigo que
  // EscanearQR.tsx: busca el pedido por id + restaurante, para verificar que es
  // suyo antes de sentarlo) y despues lo sienta.
  const { data: pedidoEscaneado, error: eEscanear } = await staff
    .from('pedidos')
    .select('*, pedido_items(*)')
    .eq('id', pedidoId)
    .eq('restaurante_id', REST)
    .maybeSingle();
  check(!eEscanear && pedidoEscaneado?.cliente_nombre === 'Cliente Reserva Test',
    'el mesero escanea el ticket QR y ve el nombre del cliente para verificar que es el mismo' + (eEscanear ? ' -> ' + eEscanear.message : ''));

  const { data: cuentaCreada, error: eSentar } = await staff.rpc('sentar_reserva', { p_pedido_id: pedidoId, p_mesa: MESA });
  check(!eSentar && !!cuentaCreada, 'el staff del restaurante SI puede sentar la reserva' + (eSentar ? ' -> ' + eSentar.message : ''));
  cuentaId = cuentaCreada;

  // pedido_seguimiento despues de sentarse: ya trae mesa + cuenta_id (para que
  // la pantalla del cliente le muestre el link a su cuenta de mesa).
  const { data: segDespues } = await anon.rpc('pedido_seguimiento', { p_pedido_id: pedidoId });
  const segDespuesFila = segDespues?.[0];
  check(segDespuesFila?.mesa === MESA && segDespuesFila?.cuenta_id === cuentaId,
    'pedido_seguimiento despues de sentarse: mesa y cuenta_id ya aparecen (la pantalla del cliente puede linkear a su mesa)');

  const { data: pedTrasSentar } = await svc.from('pedidos').select('cuenta_id,mesa').eq('id', pedidoId).maybeSingle();
  check(pedTrasSentar?.cuenta_id === cuentaId, 'el pedido queda ligado a la cuenta de mesa creada');
  check(pedTrasSentar?.mesa === MESA, 'el pedido queda con el numero de mesa correcto');

  const { data: cuentaFila } = await svc.from('cuentas_mesa').select('*').eq('id', cuentaId).maybeSingle();
  check(cuentaFila?.restaurante_id === REST && cuentaFila?.mesa === MESA, 'la cuenta_mesa es del restaurante y la mesa correctos');
  check(cuentaFila?.comensales === 4, 'la cuenta_mesa hereda personas=4 como comensales');
  check(cuentaFila?.estado !== 'cerrada', 'la cuenta queda abierta');

  const { data: comensales } = await svc.from('comensales_mesa').select('*').eq('cuenta_id', cuentaId);
  check((comensales ?? []).length === 1 && comensales[0].nombre === 'Cliente Reserva Test', 'el cliente de la reserva queda como primer comensal');

  // 5) La mesa ya sentada se encuentra por el mismo camino que un QR fisico
  // (cuenta_mesa_activa): sin esto, el cliente no podria ver/agregar a su cuenta.
  const { data: activaViaQR } = await anon.rpc('cuenta_mesa_activa', { p_restaurante_id: REST, p_mesa: MESA });
  check(activaViaQR?.[0]?.id === cuentaId, 'cuenta_mesa_activa (el mismo camino que un QR fisico) encuentra la mesa recien sentada');

  // 6) Una vez sentado, puede pedir MAS a la misma cuenta (la razon de ser de
  // convertirlo en mesa real: bebidas, postre, etc. via el camino normal de mesa).
  const { data: creadoExtra, error: eExtra } = await anon.rpc('crear_pedido', {
    p_restaurante_id: REST,
    p_cliente_nombre: 'Cliente Reserva Test',
    p_cliente_telefono: '04120001111',
    p_tipo_entrega: 'mesa',
    p_metodo_pago: 'efectivo',
    p_items: [{ producto_id: PROD_ID, cantidad: 1 }],
    p_mesa: MESA,
  });
  check(!eExtra, 'una vez sentado, se puede agregar otro pedido a la misma mesa' + (eExtra ? ' -> ' + eExtra.message : ''));
  check(creadoExtra?.[0]?.cuenta_id === cuentaId, 'el pedido extra cae en LA MISMA cuenta que la reserva sentada');
  if (creadoExtra?.[0]?.pedido_id) await svc.from('pedidos').delete().eq('id', creadoExtra[0].pedido_id);

  // 7) No se puede sentar dos veces la misma reserva.
  const { error: eDobleSentar } = await staff.rpc('sentar_reserva', { p_pedido_id: pedidoId, p_mesa: MESA });
  check(!!eDobleSentar, 'no se puede sentar la misma reserva dos veces' + (eDobleSentar ? '' : ' -> FALLO: no dio error'));

  // 8) Una reserva cancelada no se puede sentar (probado con un pedido nuevo).
  const { data: creado2 } = await anon.rpc('crear_pedido', {
    p_restaurante_id: REST,
    p_cliente_nombre: 'Cliente Reserva Cancelada',
    p_cliente_telefono: '04120002222',
    p_tipo_entrega: 'reserva',
    p_metodo_pago: 'efectivo',
    p_items: [{ producto_id: PROD_ID, cantidad: 1 }],
    p_personas: 2,
  });
  const pedidoId2 = creado2?.[0]?.pedido_id;
  await staff.rpc('cambiar_estado_pedido', { p_pedido_id: pedidoId2, p_nuevo_estado: 'cancelado' });
  const { error: eSentarCancelado } = await staff.rpc('sentar_reserva', { p_pedido_id: pedidoId2, p_mesa: 'TR91' });
  check(!!eSentarCancelado, 'una reserva cancelada no se puede sentar' + (eSentarCancelado ? '' : ' -> FALLO: no dio error'));
  if (pedidoId2) await svc.from('pedidos').delete().eq('id', pedidoId2);
} catch (e) {
  console.log('  XX  Excepción: ' + e.message);
  fallos++;
} finally {
  await limpiar();
  console.log('\nLimpieza hecha (pedidos, cuenta de mesa, comensal y usuarios de prueba fuera)');
}

console.log(fallos === 0 ? '\nRESERVA -> MESA OK' : `\nRESERVA -> MESA: ${fallos} FALLO(S)`);
process.exit(fallos === 0 ? 0 : 1);
