-- =============================================================================
-- PROPINAS + RENDIMIENTO POR MESERO
--   1) pagos_mesa.propina_usd: dinero EXTRA sobre la comida (no afecta el cierre,
--      que sigue mirando la comida via fn_mesa_toda_pagada).
--   2) cobrar_y_cerrar_mesa acepta p_propina. Se DROPea la firma vieja
--      (uuid,text,text) para NO crear overload (PostgREST -> HTTP 300).
--   3) rendimiento_meseros: por mesero ASIGNADO a la mesa, cuantas mesas atendio,
--      pedidos, ventas cobradas y propinas. Solo dueño/admin.
-- =============================================================================

alter table public.pagos_mesa
  add column if not exists propina_usd numeric(10,2) not null default 0;

-- Reemplazo de firma: (uuid,text,text) -> (uuid,text,text,numeric).
drop function if exists public.cobrar_y_cerrar_mesa(uuid, text, text);

create or replace function public.cobrar_y_cerrar_mesa(
  p_cuenta_id uuid,
  p_metodo text,
  p_referencia text default null,
  p_propina numeric default 0
)
returns table(pago_id uuid, monto_usd numeric, cerrada boolean)
language plpgsql
security definer
set search_path to 'public'
as $function$
declare
  v_cta           public.cuentas_mesa%rowtype;
  v_monto         numeric(10,2);
  v_propina       numeric(10,2) := round(greatest(coalesce(p_propina, 0), 0), 2);
  v_pago          uuid := null;
  v_mesero_id     uuid;
  v_mesero_nombre text;
  v_verif         boolean;
  v_cerrar        boolean;
begin
  select * into v_cta from public.cuentas_mesa where id = p_cuenta_id for update;
  if not found or v_cta.estado = 'cerrada' then raise exception 'La cuenta no esta disponible'; end if;
  if not (fn_es_staff_de(v_cta.restaurante_id) or fn_es_admin()) then raise exception 'Sin permiso'; end if;
  if p_metodo not in ('pago_movil','efectivo','transferencia','zelle','punto_venta') then raise exception 'Metodo de pago invalido'; end if;
  v_verif := (p_metodo = 'efectivo') or fn_es_dueno_de(v_cta.restaurante_id) or fn_es_admin();

  select coalesce(sum(s.total_usd), 0) into v_monto
    from (
      select p.total_usd from public.pedidos p
       where p.cuenta_id = p_cuenta_id and p.pago_mesa_id is null and p.estado <> 'cancelado'
       for update
    ) s;

  select pf.id, coalesce(nullif(trim(pf.nombre), ''), 'Mesero')
    into v_mesero_id, v_mesero_nombre from public.perfiles pf where pf.id = auth.uid();

  -- Inserta el pago si hay comida por cobrar O si dejaron propina (propina sola).
  if v_monto > 0 or v_propina > 0 then
    insert into public.pagos_mesa (cuenta_id, restaurante_id, monto_usd, propina_usd, metodo, referencia, mesero_id, mesero_nombre, verificado)
      values (p_cuenta_id, v_cta.restaurante_id, v_monto, v_propina, p_metodo, nullif(trim(coalesce(p_referencia, '')), ''), v_mesero_id, v_mesero_nombre, v_verif)
      returning id into v_pago;
    update public.pedidos set pago_mesa_id = v_pago
      where cuenta_id = p_cuenta_id and pago_mesa_id is null and estado <> 'cancelado';
  end if;

  -- Cierra solo si la COMIDA quedo pagada y verificada (la propina no cuenta aca).
  v_cerrar := fn_mesa_toda_pagada(p_cuenta_id);
  if v_cerrar then
    update public.cuentas_mesa set estado = 'cerrada', cerrada_en = now() where id = p_cuenta_id;
  end if;

  return query select v_pago, v_monto, v_cerrar;
end;
$function$;

grant execute on function public.cobrar_y_cerrar_mesa(uuid, text, text, numeric) to authenticated;

-- Rendimiento por mesero (el ASIGNADO a la mesa). Solo dueño/admin.
create or replace function public.rendimiento_meseros(
  p_restaurante_id uuid,
  p_desde timestamptz default null
)
returns table(
  mesero_id uuid,
  nombre text,
  mesas bigint,
  pedidos bigint,
  ventas_usd numeric,
  propinas_usd numeric
)
language plpgsql
security definer
set search_path to 'public'
as $function$
begin
  if not (fn_es_dueno_de(p_restaurante_id) or fn_es_admin()) then
    raise exception 'Sin permiso';
  end if;
  return query
  with mesas_m as (
    select c.id, c.mesero_id
      from public.cuentas_mesa c
     where c.restaurante_id = p_restaurante_id
       and c.mesero_id is not null
       and (p_desde is null or c.abierta_en >= p_desde)
  )
  select
    pf.id,
    coalesce(nullif(trim(pf.nombre), ''), 'Mesero'),
    (select count(*) from mesas_m m where m.mesero_id = pf.id),
    (select count(*) from public.pedidos pd join mesas_m m on m.id = pd.cuenta_id
       where m.mesero_id = pf.id and pd.estado <> 'cancelado'),
    (select coalesce(sum(pg.monto_usd), 0) from public.pagos_mesa pg join mesas_m m on m.id = pg.cuenta_id
       where m.mesero_id = pf.id),
    (select coalesce(sum(pg.propina_usd), 0) from public.pagos_mesa pg join mesas_m m on m.id = pg.cuenta_id
       where m.mesero_id = pf.id)
  from public.perfiles pf
  where pf.restaurante_id = p_restaurante_id
    and pf.rol = 'staff'
  order by 5 desc, 2;
end;
$function$;

grant execute on function public.rendimiento_meseros(uuid, timestamptz) to authenticated;
