-- ============================================================
-- Gustito Xpress — PAGO POR PERSONA EN LINEA (cuentas separadas fase 2).
--
-- El cliente paga SU parte desde su telefono (pago movil / zelle / transf.)
-- con referencia y captura. El pago queda POR REVISAR: bloquea los pedidos de
-- esa persona (pago_mesa_id) para que el mesero no los cobre otra vez, pero NO
-- cuenta como pagado hasta que el mesero lo VERIFICA. Si lo rechaza, se
-- desbloquean y quedan por cobrar de nuevo.
--
-- "pagado" = ligado a un pago VERIFICADO. Los cobros del mesero (cobro por
-- partes) nacen verificados (default true), asi el comportamiento actual no
-- cambia; solo los pagos del cliente entran en 'por revisar'.
-- ============================================================

-- ---- pagos_mesa: verificado + captura + a que persona ----
alter table public.pagos_mesa add column if not exists verificado boolean not null default true;
alter table public.pagos_mesa add column if not exists comprobante_url text;
alter table public.pagos_mesa add column if not exists comensal_id uuid references public.comensales_mesa(id) on delete set null;
create index if not exists idx_pagos_mesa_por_revisar on public.pagos_mesa (restaurante_id) where (verificado = false);

-- ---- pagar_parte_cliente: el cliente paga su parte (queda por revisar) ----
create or replace function public.pagar_parte_cliente(
  p_cuenta_id uuid, p_comensal_id uuid, p_metodo text,
  p_referencia text default null, p_comprobante_url text default null
)
returns table(pago_id uuid, monto_usd numeric)
language plpgsql security definer set search_path to 'public'
as $function$
declare
  v_rest  uuid;
  v_monto numeric(10,2);
  v_n     int;
  v_pago  uuid;
begin
  select restaurante_id into v_rest from public.cuentas_mesa where id = p_cuenta_id and estado <> 'cerrada';
  if v_rest is null then raise exception 'La cuenta no esta disponible'; end if;
  if p_metodo not in ('pago_movil','zelle','transferencia') then
    raise exception 'Metodo de pago en linea invalido';
  end if;
  perform 1 from public.comensales_mesa cm where cm.id = p_comensal_id and cm.cuenta_id = p_cuenta_id;
  if not found then raise exception 'La persona no pertenece a esta mesa'; end if;

  -- Pedidos de esa persona, sin cobrar y no cancelados: se bloquean (lock).
  select count(*), coalesce(sum(s.total_usd), 0) into v_n, v_monto
    from (
      select p.total_usd from public.pedidos p
       where p.cuenta_id = p_cuenta_id
         and p.comensal_id = p_comensal_id
         and p.pago_mesa_id is null
         and p.estado <> 'cancelado'
       for update
    ) s;
  if v_n = 0 or v_monto <= 0 then
    raise exception 'Esta persona no tiene nada pendiente por pagar';
  end if;

  insert into public.pagos_mesa (cuenta_id, restaurante_id, monto_usd, metodo, referencia, comprobante_url, comensal_id, verificado)
    values (p_cuenta_id, v_rest, v_monto, p_metodo,
            nullif(trim(coalesce(p_referencia, '')), ''),
            nullif(trim(coalesce(p_comprobante_url, '')), ''),
            p_comensal_id, false)
    returning id into v_pago;

  update public.pedidos set pago_mesa_id = v_pago
    where cuenta_id = p_cuenta_id and comensal_id = p_comensal_id and pago_mesa_id is null and estado <> 'cancelado';

  return query select v_pago, v_monto;
end;
$function$;
grant execute on function public.pagar_parte_cliente(uuid, uuid, text, text, text) to anon, authenticated;

-- ---- verificar_pago_cliente: el mesero confirma o rechaza ----
create or replace function public.verificar_pago_cliente(p_pago_id uuid, p_ok boolean)
returns void
language plpgsql security definer set search_path to 'public'
as $function$
declare v_rest uuid; v_verif boolean;
begin
  select restaurante_id, verificado into v_rest, v_verif from public.pagos_mesa where id = p_pago_id;
  if v_rest is null then raise exception 'Pago no existe'; end if;
  if not (fn_es_staff_de(v_rest) or fn_es_admin()) then raise exception 'Sin permiso'; end if;
  if v_verif then raise exception 'Ese pago ya estaba verificado'; end if;
  if p_ok then
    update public.pagos_mesa set verificado = true where id = p_pago_id;
  else
    -- Rechazado: los pedidos vuelven a quedar por cobrar y se borra el pago.
    update public.pedidos set pago_mesa_id = null where pago_mesa_id = p_pago_id;
    delete from public.pagos_mesa where id = p_pago_id;
  end if;
end;
$function$;
grant execute on function public.verificar_pago_cliente(uuid, boolean) to authenticated;

-- ---- pagos_por_revisar: los pagos en linea pendientes (para el panel) ----
create or replace function public.pagos_por_revisar(p_restaurante_id uuid)
returns table(pago_id uuid, cuenta_id uuid, mesa text, comensal_nombre text, monto_usd numeric, metodo text, referencia text, comprobante_url text, creado_en timestamptz)
language sql stable security definer set search_path to 'public'
as $function$
  select pm.id, pm.cuenta_id, c.mesa, cm.nombre, pm.monto_usd, pm.metodo, pm.referencia, pm.comprobante_url, pm.creado_en
  from public.pagos_mesa pm
  join public.cuentas_mesa c on c.id = pm.cuenta_id
  left join public.comensales_mesa cm on cm.id = pm.comensal_id
  where pm.restaurante_id = p_restaurante_id
    and pm.verificado = false
    and (fn_es_staff_de(pm.restaurante_id) or fn_es_admin())
  order by pm.creado_en;
$function$;
grant execute on function public.pagos_por_revisar(uuid) to authenticated;

-- ---- cuenta_mesa: "pagado" = verificado; agrega estado por revisar ----
create or replace function public.cuenta_mesa(p_cuenta_id uuid)
returns table(
  id uuid, mesa text, estado text, restaurante_nombre text, restaurante_slug text,
  restaurante_color text, restaurante_telefono text, tasa_bs numeric, total_usd numeric,
  metodo_pago text, metodos_pago jsonb, promedio_min integer, pedidos jsonb, mesero_nombre text,
  modo_cuenta text, comensales jsonb, llamadas jsonb, tiempo_estimado_min integer
)
language sql stable security definer set search_path to 'public'
as $function$
  select c.id, c.mesa, c.estado,
         r.nombre, r.slug, r.color_primario, r.telefono,
         r.tasa_bs,
         coalesce((select sum(p.total_usd) from public.pedidos p where p.cuenta_id = c.id and p.estado <> 'cancelado'), 0),
         c.metodo_pago, r.metodos_pago,
         coalesce(r.sala_promedio_min, 10),
         coalesce((
           select jsonb_agg(jsonb_build_object(
             'id', p.id, 'codigo', p.codigo, 'estado', p.estado, 'total_usd', p.total_usd,
             'cliente', p.cliente_nombre,
             'pagado', (p.pago_mesa_id is not null and coalesce((select pm.verificado from public.pagos_mesa pm where pm.id = p.pago_mesa_id), false)),
             'pago_estado', (case when p.pago_mesa_id is null then null
                                  when coalesce((select pm.verificado from public.pagos_mesa pm where pm.id = p.pago_mesa_id), false) then 'pagado'
                                  else 'por_revisar' end),
             'comensal_id', p.comensal_id,
             'comensal', (select cm.nombre from public.comensales_mesa cm where cm.id = p.comensal_id),
             'items', coalesce((select jsonb_agg(jsonb_build_object(
                         'nombre', it.nombre, 'cantidad', it.cantidad, 'precio_usd', it.precio_usd, 'nota', it.nota))
                       from public.pedido_items it where it.pedido_id = p.id), '[]'::jsonb)
           ) order by p.recibido_en)
           from public.pedidos p where p.cuenta_id = c.id
         ), '[]'::jsonb),
         c.mesero_nombre,
         c.modo_cuenta,
         coalesce((
           select jsonb_agg(jsonb_build_object(
             'id', cm.id, 'nombre', cm.nombre, 'orden', cm.orden,
             'total_usd', coalesce((select sum(p.total_usd) from public.pedidos p where p.comensal_id = cm.id and p.estado <> 'cancelado'), 0),
             'pagado_usd', coalesce((select sum(p.total_usd) from public.pedidos p join public.pagos_mesa pm on pm.id = p.pago_mesa_id where p.comensal_id = cm.id and p.estado <> 'cancelado' and pm.verificado), 0),
             'por_revisar_usd', coalesce((select sum(p.total_usd) from public.pedidos p join public.pagos_mesa pm on pm.id = p.pago_mesa_id where p.comensal_id = cm.id and p.estado <> 'cancelado' and not pm.verificado), 0)
           ) order by cm.orden)
           from public.comensales_mesa cm where cm.cuenta_id = c.id
         ), '[]'::jsonb),
         coalesce((select jsonb_agg(l.tipo) from public.llamadas_mesa l where l.cuenta_id = c.id and l.atendida_en is null), '[]'::jsonb),
         (select max(p.tiempo_estimado_min) from public.pedidos p
           where p.cuenta_id = c.id and p.estado in ('recibido','confirmado','preparando'))
  from public.cuentas_mesa c
  join public.restaurantes r on r.id = c.restaurante_id
  where c.id = p_cuenta_id;
$function$;
grant execute on function public.cuenta_mesa(uuid) to anon, authenticated;

-- ---- mis_cuentas_mesa: pagado_usd = verificado; + por_revisar_usd ----
drop function if exists public.mis_cuentas_mesa(uuid);
create function public.mis_cuentas_mesa(p_restaurante_id uuid)
returns table(
  id uuid, mesa text, estado text, total_usd numeric, tasa_bs numeric,
  abierta_en timestamptz, pago_solicitado_en timestamptz, metodo_pago text,
  referencia text, comprobante_url text, n_pedidos integer,
  mesero_id uuid, mesero_nombre text, pagado_usd numeric,
  comensales integer, modo_cuenta text, por_revisar_usd numeric
)
language sql stable security definer set search_path to 'public'
as $function$
  select c.id, c.mesa, c.estado,
    coalesce((select sum(p.total_usd) from public.pedidos p where p.cuenta_id = c.id and p.estado <> 'cancelado'), 0),
    r.tasa_bs, c.abierta_en, c.pago_solicitado_en, c.metodo_pago, c.referencia, c.comprobante_url,
    (select count(*)::int from public.pedidos p where p.cuenta_id = c.id and p.estado <> 'cancelado'),
    c.mesero_id, c.mesero_nombre,
    coalesce((select sum(pm.monto_usd) from public.pagos_mesa pm where pm.cuenta_id = c.id and pm.verificado), 0),
    c.comensales, c.modo_cuenta,
    coalesce((select sum(pm.monto_usd) from public.pagos_mesa pm where pm.cuenta_id = c.id and not pm.verificado), 0)
  from public.cuentas_mesa c
  join public.restaurantes r on r.id = c.restaurante_id
  where c.restaurante_id = p_restaurante_id
    and c.estado <> 'cerrada'
    and (fn_es_staff_de(c.restaurante_id) or fn_es_admin())
  order by c.abierta_en;
$function$;
grant execute on function public.mis_cuentas_mesa(uuid) to anon, authenticated;
