-- MESAS OLVIDADAS (2026-07-27, pedido de Gilberto al supervisar Arepa Power)
-- Caso real: 4 mesas abiertas el 25/07 entre 6:26 y 6:48 pm, cerradas TODAS de
-- golpe el 27/07 a las 6:49 pm. 48 horas abiertas, tres con consumo ($11, $9,
-- $10) y una que nunca pidio nada. Nadie le aviso a Diego, y a los dos dias ya
-- no se sabe si esa gente pago o se fue sin pagar.
-- Dos problemas distintos, dos soluciones distintas:
--   1. Mesa que nadie uso (escanearon el QR y se fueron): se cierra SOLA. No
--      hay plata de por medio. 5 minutos si la abrio el cliente; 30 si la abrio
--      el personal (la mesera puede estar tomando la nota todavia).
--      Cerrarla no le quita nada al cliente: si despues pide, crear_pedido le
--      abre la cuenta de nuevo.
--   2. Mesa CON consumo sin cobrar que amanece abierta: NO se puede cerrar en
--      silencio, ahi hay plata. Se cierra marcada como PERDIDA (mismo mecanismo
--      de marcar_perdida_mesa) para que quede CONTADA como perdida y no se
--      cuele como venta buena ni desaparezca del radar.
begin;

-- 1. LA MESA QUE NADIE USO: se cierra sola (corre cada minuto).
create or replace function public.fn_cerrar_mesas_vacias()
returns int
language plpgsql
security definer
set search_path to 'public'
as $fn$
declare v_n int;
begin
  update public.cuentas_mesa c
     set estado = 'cerrada', cerrada_en = now()
   where c.estado <> 'cerrada'
     and not exists (
       select 1 from public.pedidos p
        where p.cuenta_id = c.id and p.estado <> 'cancelado'
     )
     and c.abierta_en < now() - (
       case when c.mesero_id is null then interval '5 minutes' else interval '30 minutes' end
     );
  get diagnostics v_n = row_count;
  return v_n;
end;
$fn$;

-- 2. LA MESA CON COMIDA QUE AMANECIO ABIERTA: se cierra como PERDIDA.
-- Corre de madrugada (5:00 am hora Venezuela): a esa hora nadie esta operando,
-- asi que lo que siga abierto con consumo sin cobrar es una mesa olvidada.
create or replace function public.fn_cerrar_mesas_olvidadas()
returns int
language plpgsql
security definer
set search_path to 'public'
as $fn$
declare
  v_cta    record;
  v_monto  numeric(10,2);
  v_ids    uuid[];
  v_pago   uuid;
  v_n      int := 0;
begin
  for v_cta in
    select c.id, c.restaurante_id, c.mesa
      from public.cuentas_mesa c
     where c.estado <> 'cerrada'
       and c.abierta_en < now() - interval '6 hours'
       and exists (
         select 1 from public.pedidos p
          where p.cuenta_id = c.id and p.estado <> 'cancelado'
       )
     for update
  loop
    select coalesce(sum(p.total_usd), 0), array_agg(p.id)
      into v_monto, v_ids
      from public.pedidos p
     where p.cuenta_id = v_cta.id
       and p.estado <> 'cancelado'
       and p.pago_mesa_id is null;

    -- Lo que quedo sin cobrar se anota como perdida, con su motivo, para que el
    -- dueño lo vea en el reporte y no se lo trague la caja como venta buena.
    if coalesce(v_monto, 0) > 0 then
      insert into public.pagos_mesa
        (cuenta_id, restaurante_id, monto_usd, metodo, nota, mesero_nombre, verificado)
      values
        (v_cta.id, v_cta.restaurante_id, v_monto, 'perdida',
         'Cerrada sola: la mesa quedo abierta de un dia para otro y nadie la cobro',
         'Sistema', true)
      returning id into v_pago;
      update public.pedidos set pago_mesa_id = v_pago where id = any(v_ids);
    end if;

    update public.cuentas_mesa
       set estado = 'cerrada', cerrada_en = now()
     where id = v_cta.id;
    v_n := v_n + 1;
  end loop;
  return v_n;
end;
$fn$;

revoke execute on function public.fn_cerrar_mesas_vacias() from anon, authenticated;
revoke execute on function public.fn_cerrar_mesas_olvidadas() from anon, authenticated;

select cron.unschedule(jobid) from cron.job where jobname in ('cerrar-mesas-vacias', 'cerrar-mesas-olvidadas');
select cron.schedule('cerrar-mesas-vacias', '* * * * *', $cmd$select public.fn_cerrar_mesas_vacias()$cmd$);
-- 09:00 UTC = 5:00 am en Venezuela
select cron.schedule('cerrar-mesas-olvidadas', '0 9 * * *', $cmd$select public.fn_cerrar_mesas_olvidadas()$cmd$);

commit;
