// Prueba VIVA (demo-gustito) de los dos flujos nuevos de v2.6.6:
//   1) VENTA DE CAJA: nace ENTREGADA (no estorba en activos), comanda con
//      membrete CAJA (sin "PARA RETIRAR"), SIN ticket de despacho ni copia.
//   2) COPIA-NEGOCIO de MESA: NO sale con la comanda; sale al COBRAR Y LIBERAR
//      (cuenta cerrada), con el cobro real (metodo, referencia, propina).
// Env: SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_KEY.
import { createClient } from '@supabase/supabase-js';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { crearImpresoraVirtual } from './impresora_virtual.mjs';
import { iniciarCerebrito } from '../dist/motor.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 = (ok, msg) => {
  console.log(`  ${ok ? 'OK ' : 'XX '} ${msg}`);
  if (!ok) fallos += 1;
};
const espera = (ms) => new Promise((r) => setTimeout(r, ms));
const hasta = async (fn, tope = 30_000, paso = 500) => {
  const fin = Date.now() + tope;
  while (Date.now() < fin) {
    if (await fn()) return true;
    await espera(paso);
  }
  return await fn();
};
const plano = (t) => t.normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/\s+/g, ' ');

const svc = createClient(URL, SERVICE, { auth: { persistSession: false } });
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;

// Producto que SI se cocina (categoria imprime).
const { data: prods } = await svc
  .from('productos')
  .select('id,nombre,precio_usd,disponible,categoria:categorias(a_cocina)')
  .eq('restaurante_id', REST)
  .eq('disponible', true)
  .limit(20);
const comida = (prods ?? []).find((p) => p.categoria?.a_cocina !== false);
if (!comida) {
  console.log('El demo no tiene productos cocinables');
  process.exit(1);
}

const EMAIL = 'cerebrito.caja.test@gustitoxpress.app';
const CLAVE = 'PruebaCaja2026!';
const MESA = '77';
let uid = null;
let motor = null;
let impCocina = null;
let impCaja = null;
let pedidoCajaId = null;
let cuentaId = null;
const carpetaTmp = mkdtempSync(join(tmpdir(), 'cerebrito-caja-'));

async function limpiar() {
  try {
    if (cuentaId) {
      const { data: peds } = await svc.from('pedidos').select('id').eq('cuenta_id', cuentaId);
      const ids = (peds ?? []).map((p) => p.id);
      if (ids.length) {
        await svc.from('pedido_items').delete().in('pedido_id', ids);
        await svc.from('pagos').delete().in('pedido_id', ids);
        await svc.from('pedidos').delete().in('id', ids);
      }
      await svc.from('pagos_mesa').delete().eq('cuenta_id', cuentaId);
      await svc.from('cuentas_mesa').delete().eq('id', cuentaId);
    }
    if (pedidoCajaId) {
      await svc.from('pedido_items').delete().eq('pedido_id', pedidoCajaId);
      await svc.from('pagos').delete().eq('pedido_id', pedidoCajaId);
      await svc.from('pedidos').delete().eq('id', pedidoCajaId);
    }
    if (uid) await svc.auth.admin.deleteUser(uid).catch(() => {});
  } catch (e) {
    console.log('Limpieza con tropiezo:', e.message);
  }
  motor?.detener();
  impCocina?.cerrar?.();
  impCaja?.cerrar?.();
  try {
    rmSync(carpetaTmp, { recursive: true, force: true });
  } catch {
    /* tmp del SO */
  }
}

try {
  // Encargado temporal (mismo rol con el que entra el cerebrito de verdad).
  const { data: lista } = await svc.auth.admin.listUsers();
  for (const u of lista?.users ?? []) {
    if (u.email === EMAIL) await svc.auth.admin.deleteUser(u.id).catch(() => {});
  }
  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);
  uid = u.user.id;
  await svc.from('perfiles').upsert({ id: uid, rol: 'encargado', restaurante_id: REST, nombre: 'Caja Test' });

  impCocina = await crearImpresoraVirtual(9320);
  impCaja = await crearImpresoraVirtual(9322);
  motor = await iniciarCerebrito(
    {
      supabaseUrl: URL,
      anonKey: ANON,
      correo: EMAIL,
      clave: CLAVE,
      impresoras: [
        { puesto: 'Cocina', tipo: 'tcp', host: '127.0.0.1', puerto: 9320 },
        { puesto: 'Barra', tipo: 'tcp', host: '127.0.0.1', puerto: 9320 },
        { puesto: 'Caja', tipo: 'tcp', host: '127.0.0.1', puerto: 9322 },
      ],
      // pickup INCLUIDO a proposito: la venta de caja igual NO debe sacar despacho.
      despacho: { puesto: 'Caja', tipos: ['delivery', 'pickup', 'mesa'] },
      carpetaEstado: carpetaTmp,
    },
    { log: (m) => console.log('   [motor] ' + m) },
  );

  const enc = createClient(URL, ANON, { auth: { persistSession: false } });
  await enc.auth.signInWithPassword({ email: EMAIL, password: CLAVE });

  // ===== 1) VENTA DE CAJA =====
  const { data: venta, error: eVenta } = await enc.rpc('crear_pedido', {
    p_restaurante_id: REST,
    p_cliente_nombre: 'Cliente en caja',
    p_cliente_telefono: '04120000077',
    p_tipo_entrega: 'pickup',
    p_metodo_pago: 'efectivo',
    p_items: [{ producto_id: comida.id, cantidad: 1 }],
    p_venta_caja: true,
  });
  check(!eVenta && !!venta?.[0]?.pedido_id, 'crear_pedido con p_venta_caja funciona' + (eVenta ? ' -> ' + eVenta.message : ''));
  pedidoCajaId = venta?.[0]?.pedido_id;
  const codigoCaja = venta?.[0]?.codigo ?? '';

  const { data: fila } = await svc
    .from('pedidos')
    .select('estado,origen,entregado_en,confirmado_en,pagos(estado)')
    .eq('id', pedidoCajaId)
    .maybeSingle();
  check(fila?.estado === 'entregado', 'la venta de caja nace ENTREGADA (no estorba en pedidos activos)');
  check(fila?.origen === 'caja' && !!fila?.entregado_en, 'queda marcada origen=caja con su hora de entrega');
  check(fila?.pagos?.[0]?.estado === 'confirmado', 'el pago nace CONFIRMADO (la caja cobro y verifico)');

  const llegoCaja = await hasta(() => impCocina.tickets.some((t) => plano(t).includes(`#${codigoCaja}`)), 30_000);
  check(llegoCaja, 'la comanda de la venta de caja salio en cocina');
  const tComanda = plano(impCocina.tickets.filter((t) => plano(t).includes(`#${codigoCaja}`)).join('\n'));
  check(tComanda.includes('CAJA'), 'la comanda dice CAJA en el membrete');
  check(!tComanda.includes('PARA RETIRAR'), 'ya NO dice "PARA RETIRAR"');
  const llegoCopiaCaja = await hasta(() => impCaja.tickets.some((t) => plano(t).includes(`#${codigoCaja}`)), 30_000);
  check(llegoCopiaCaja, 'la venta de caja deja su COPIA-NEGOCIO (respaldo del negocio)');
  const tCopiaCaja = plano(impCaja.tickets.filter((t) => plano(t).includes(`#${codigoCaja}`)).join('\n'));
  check(tCopiaCaja.includes('COPIA-NEGOCIO') && !tCopiaCaja.includes('DESPACHO'), 'es SOLO la copia, sin ticket de cliente (esta parado ahi)');
  check(tCopiaCaja.includes('Pagado: EFECTIVO') && !tCopiaCaja.includes('COBRA EN EFECTIVO'), 'la copia dice Pagado (ya la caja cobro), no "cobra en efectivo"');

  // ===== 2) COPIA-NEGOCIO DE MESA AL COBRAR =====
  await svc.from('cuentas_mesa').delete().eq('restaurante_id', REST).eq('mesa', MESA);
  const { data: pm, error: ePm } = await enc.rpc('crear_pedido', {
    p_restaurante_id: REST,
    p_cliente_nombre: 'Sin nombre',
    p_cliente_telefono: '',
    p_tipo_entrega: 'mesa',
    p_metodo_pago: 'efectivo',
    p_items: [{ producto_id: comida.id, cantidad: 2 }],
    p_mesa: MESA,
  });
  check(!ePm && !!pm?.[0]?.cuenta_id, 'pedido de mesa creado (encargado -> confirmado)' + (ePm ? ' -> ' + ePm.message : ''));
  cuentaId = pm?.[0]?.cuenta_id;

  const esCopiaMesa = (t) => plano(t).includes('COPIA-NEGOCIO') && plano(t).includes(`MESA ${MESA}`);
  const llegoLote = await hasta(() => impCocina.tickets.some((t) => plano(t).includes(`MESA ${MESA}`)), 30_000);
  check(llegoLote, 'la comanda de la mesa salio en cocina (lote 5s)');
  check(!impCaja.tickets.some(esCopiaMesa), 'la copia del negocio NO salio con la comanda (antes salia y con "cobra en efectivo" inventado)');

  const { data: cobro, error: eCobro } = await enc.rpc('cobrar_y_cerrar_mesa', {
    p_cuenta_id: cuentaId,
    p_metodo: 'efectivo',
    p_referencia: 'REF123',
    p_propina: 1,
  });
  check(!eCobro && cobro?.[0]?.cerrada === true, 'cobrar_y_cerrar_mesa cerro la cuenta' + (eCobro ? ' -> ' + eCobro.message : ''));

  const llegoCopia = await hasta(() => impCaja.tickets.some(esCopiaMesa), 30_000);
  check(llegoCopia, 'al cobrar y liberar SI salio la COPIA-NEGOCIO en caja');
  const tCopia = plano(impCaja.tickets.filter(esCopiaMesa).join('\n'));
  check(tCopia.includes(`MESA ${MESA}`), 'la copia dice la mesa');
  check(tCopia.includes(plano(`2x ${comida.nombre}`)), 'la copia trae los renglones consumidos');
  check(tCopia.includes('Pagado: EFECTIVO'), 'la copia trae el cobro REAL (no "cobra en efectivo" inventado)');
  check(tCopia.includes('REF123'), 'la copia trae la referencia');
  check(tCopia.includes('Propina: $1.00'), 'la copia trae la propina');
  check(tCopia.includes('ESTE TICKET NO ES FACTURA'), 'la copia trae la leyenda fiscal');

  // ===== 3) Antirepetida: un barrido completo despues, nada se duplica =====
  await espera(22_000);
  const veces = (tickets, txt) => tickets.reduce((n, t) => n + (plano(t).includes(txt) ? 1 : 0), 0);
  check(veces(impCocina.tickets, `#${codigoCaja}`) === 1, 'la comanda de caja no se repitio tras el barrido');
  check(veces(impCaja.tickets, `#${codigoCaja}`) === 1, 'la copia de la venta de caja no se repitio tras el barrido');
  check(
    impCaja.tickets.filter((t) => plano(t).includes('COPIA-NEGOCIO') && plano(t).includes(`MESA ${MESA}`)).length === 1,
    'la copia de la mesa no se repitio tras el barrido',
  );
} catch (e) {
  console.log('ERROR:', e.message);
  fallos += 1;
} finally {
  await limpiar();
}

console.log('');
console.log(fallos === 0 ? 'VENTA DE CAJA + COPIA-NEGOCIO OK' : `FALLOS: ${fallos}`);
process.exit(fallos === 0 ? 0 : 1);
