-- =============================================================================
-- NUEVO ROL "encargado": opera el negocio dia a dia (Pedidos, Cocina, Mesas,
-- POS, Menu) igual que el dueño, pero SIN lo gerencial/financiero: no ve
-- Estadisticas, reporte de pagos, Caja, Inventario, Clientes, Configuracion,
-- ni puede crear/gestionar cuentas de mesero o repartidor (eso sigue siendo
-- exclusivo del dueño). Decision de Gilberto 2026-07-22, confirmada por
-- AskUserQuestion: el encargado NO administra personal.
--
-- Estrategia: un solo valor de rol nuevo en perfiles + ajustar los helpers
-- centrales (no tocar cada RPC/policy suelta):
--  - fn_es_staff_de: pasa a incluir 'encargado' (arregla automaticamente todo
--    lo que ya usaba este helper como check generico de "trabaja aqui": tomar
--    pedidos, cocina, confirmar pagos, abrir/cobrar mesas, etc).
--  - fn_mesa_de_staff: el encargado ve/opera TODAS las mesas como el dueño,
--    NO queda atado a "su mesa" (a diferencia de un mesero comun).
--  - Los triggers de guardia de mesa ajena excluyen al encargado.
--  - categorias/productos (Menu): se abre explicitamente al encargado (antes
--    solo dueño).
--  - Lo exclusivo de dueño (Caja, Inventario, Clientes, Estadisticas, reporte
--    de pagos, Configuracion, gestion de meseros/repartidores) NO se toca:
--    sigue usando fn_es_dueno_de puro, el encargado no pasa ahi.
-- =============================================================================

-- ---- 1) Constraint: agregar 'encargado' como valor valido de perfiles.rol ----
ALTER TABLE public.perfiles DROP CONSTRAINT perfiles_rol_check;
ALTER TABLE public.perfiles ADD CONSTRAINT perfiles_rol_check
  CHECK (rol = ANY (ARRAY['dueno'::text, 'staff'::text, 'encargado'::text, 'repartidor'::text, 'comensal'::text, 'admin'::text]));

-- ---- 2) Helper nuevo ----
create or replace function public.fn_es_encargado_de(p_restaurante uuid)
returns boolean language sql stable security definer set search_path to 'public' as $fn$
  select exists (
    select 1 from public.perfiles
    where id = auth.uid()
      and restaurante_id = p_restaurante
      and rol = 'encargado'
  );
$fn$;
comment on function public.fn_es_encargado_de(uuid) is 'Rol encargado: opera el negocio (pedidos/cocina/mesas/menu) pero NO ve lo gerencial ni administra personal.';

-- ---- 3) fn_es_staff_de: "trabaja aqui" ahora incluye encargado ----
-- Esto arregla automaticamente todo lo que ya chequeaba este helper de forma
-- generica (sin relacion a aislamiento de mesa): confirmar_pago, pagos_por_revisar,
-- pagos_staff_select, repartidores_staff_select, abrir_mesa, historial_mesas,
-- sentar_reserva, cobrar_parte_mesa, cobrar_y_cerrar_mesa, asignar_repartidor,
-- aceptar_pedido, cambiar_estado_pedido.
CREATE OR REPLACE FUNCTION public.fn_es_staff_de(p_restaurante uuid)
 RETURNS boolean
 LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
AS $function$
  select exists (
    select 1 from public.perfiles
    where id = auth.uid()
      and restaurante_id = p_restaurante
      and rol in ('dueno','staff','encargado')
  );
$function$;

-- ---- 4) fn_mesa_de_staff: el encargado ve/opera TODAS las mesas (como el dueño) ----
CREATE OR REPLACE FUNCTION public.fn_mesa_de_staff(p_mesero_id uuid, p_restaurante_id uuid)
 RETURNS boolean
 LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
AS $function$
  select public.fn_es_dueno_de(p_restaurante_id)
      or public.fn_es_admin()
      or public.fn_es_encargado_de(p_restaurante_id)
      or (public.fn_es_staff_de(p_restaurante_id) and (p_mesero_id = auth.uid() or p_mesero_id is null));
$function$;

-- ---- 5) Triggers de guardia: el encargado NO queda atado a "su mesa" ----
CREATE OR REPLACE FUNCTION public.fn_guard_pedido_mesa_mio() RETURNS trigger
LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $fn$
begin
  if new.tipo_entrega = 'mesa' and new.cuenta_id is not null and auth.uid() is not null
     and public.fn_es_staff_de(new.restaurante_id)
     and not public.fn_es_dueno_de(new.restaurante_id)
     and not public.fn_es_admin()
     and not public.fn_es_encargado_de(new.restaurante_id)
     and exists (select 1 from public.cuentas_mesa c where c.id = new.cuenta_id and c.mesero_id is not null and c.mesero_id <> auth.uid())
  then
    raise exception 'Esta mesa la atiende otra persona';
  end if;
  return new;
end $fn$;

CREATE OR REPLACE FUNCTION public.fn_guard_pago_mesa_mio() RETURNS trigger
LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $fn$
begin
  if auth.uid() is not null
     and public.fn_es_staff_de(new.restaurante_id)
     and not public.fn_es_dueno_de(new.restaurante_id)
     and not public.fn_es_admin()
     and not public.fn_es_encargado_de(new.restaurante_id)
     and exists (select 1 from public.cuentas_mesa c where c.id = new.cuenta_id and c.mesero_id is not null and c.mesero_id <> auth.uid())
  then
    raise exception 'Esta mesa la atiende otra persona';
  end if;
  return new;
end $fn$;

-- ---- 6) Menu: el encargado SI puede editar categorias/productos ----
drop policy if exists categorias_dueno_escribe on public.categorias;
create policy categorias_dueno_escribe on public.categorias as permissive for all to authenticated
  using (fn_es_dueno_de(restaurante_id) or fn_es_encargado_de(restaurante_id))
  with check (fn_es_dueno_de(restaurante_id) or fn_es_encargado_de(restaurante_id));

drop policy if exists productos_dueno_escribe on public.productos;
create policy productos_dueno_escribe on public.productos as permissive for all to authenticated
  using (fn_es_dueno_de(restaurante_id) or fn_es_encargado_de(restaurante_id))
  with check (fn_es_dueno_de(restaurante_id) or fn_es_encargado_de(restaurante_id));

-- ---- 7) mis_meseros: el dueño ve tambien los encargados (para administrarlos), ----
-- gana la columna `rol` para distinguirlos en el frontend. Sigue siendo
-- SOLO DUEÑO quien puede llamarla (fn_es_dueno_de, sin encargado).
DROP FUNCTION public.mis_meseros();
CREATE OR REPLACE FUNCTION public.mis_meseros()
 RETURNS TABLE(mesero_id uuid, nombre text, telefono text, correo text, rol text, creado_en timestamp with time zone)
 LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public'
AS $function$
  select pf.id, pf.nombre, pf.telefono, u.email::text, pf.rol, pf.creado_en
  from public.perfiles pf
  join auth.users u on u.id = pf.id
  where pf.restaurante_id = fn_mi_restaurante()
    and pf.rol in ('staff','encargado')
    and (fn_es_dueno_de(pf.restaurante_id) or fn_es_admin())
  order by pf.creado_en desc;
$function$;
