-- Agrega comprobante_url (foto del pago movil) al cobro de mesa. La columna
-- pagos_mesa.comprobante_url ya existia desde antes, simplemente estas dos
-- RPC nunca la recibian (mismo patron que paso con pagos/mostrador, commit
-- b7bf17a). Se agrega como ULTIMO parametro con DEFAULT null y se hace
-- DROP+CREATE (no CREATE OR REPLACE) para no dejar un overload viejo vivo.

drop function if exists public.cobrar_y_cerrar_mesa(uuid, text, text, numeric);

create function public.cobrar_y_cerrar_mesa(
  p_cuenta_id uuid,
  p_metodo text,
  p_referencia text default null,
  p_propina numeric default 0,
  p_comprobante_url text default null
)
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, comprobante_url, mesero_id, mesero_nombre, verificado)
      values (p_cuenta_id, v_cta.restaurante_id, v_monto, v_propina, p_metodo, nullif(trim(coalesce(p_referencia, '')), ''), nullif(trim(coalesce(p_comprobante_url, '')), ''), 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$;

drop function if exists public.cobrar_parte_mesa(uuid, uuid[], text, text, text);

create function public.cobrar_parte_mesa(
  p_cuenta_id uuid,
  p_pedido_ids uuid[],
  p_metodo text,
  p_referencia text default null,
  p_nota text default null,
  p_comprobante_url text default null
)
returns table(pago_id uuid, monto_usd numeric, saldo_usd numeric)
language plpgsql
security definer
set search_path to 'public'
as $function$
declare
  v_cta            public.cuentas_mesa%rowtype;
  v_esperados      int;
  v_n              int;
  v_monto          numeric(10,2);
  v_pago           uuid;
  v_mesero_id      uuid := null;
  v_mesero_nombre  text := null;
  v_total          numeric(10,2);
  v_pagado         numeric(10,2);
  v_verif          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;
  -- Efectivo (o el dueño) = verificado; electronico del mesero = por revisar.
  v_verif := (p_metodo = 'efectivo') or fn_es_dueno_de(v_cta.restaurante_id) or fn_es_admin();

  select count(distinct u) into v_esperados from unnest(coalesce(p_pedido_ids, '{}'::uuid[])) u;
  if v_esperados = 0 then raise exception 'Elige al menos un pedido para cobrar'; end if;

  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();

  select count(*), coalesce(sum(s.total_usd), 0) into v_n, v_monto
    from (
      select p.total_usd from public.pedidos p
       where p.id = any(p_pedido_ids) and p.cuenta_id = p_cuenta_id
         and p.pago_mesa_id is null and p.estado <> 'cancelado'
       for update
    ) s;
  if v_n <> v_esperados then
    raise exception 'Algun pedido ya fue cobrado, esta cancelado o no es de esta cuenta';
  end if;
  if v_monto <= 0 then raise exception 'Nada que cobrar'; end if;

  insert into public.pagos_mesa (cuenta_id, restaurante_id, monto_usd, metodo, referencia, nota, comprobante_url, mesero_id, mesero_nombre, verificado)
    values (p_cuenta_id, v_cta.restaurante_id, v_monto, p_metodo, nullif(trim(coalesce(p_referencia,'')), ''), nullif(trim(coalesce(p_nota,'')), ''), nullif(trim(coalesce(p_comprobante_url,'')), ''), v_mesero_id, v_mesero_nombre, v_verif)
    returning id into v_pago;
  update public.pedidos set pago_mesa_id = v_pago where id = any(p_pedido_ids);

  select coalesce(sum(p.total_usd), 0) into v_total
    from public.pedidos p where p.cuenta_id = p_cuenta_id and p.estado <> 'cancelado';
  select coalesce(sum(pm.monto_usd), 0) into v_pagado
    from public.pagos_mesa pm where pm.cuenta_id = p_cuenta_id and pm.verificado;

  return query select v_pago, v_monto, greatest(v_total - v_pagado, 0::numeric);
end;
$function$;
