-- ============================================================================
-- CRUCES GLM — SUPABASE COMPLETO
-- GomezLee Marketing
-- ============================================================================
-- Ejecutar una vez en SQL Editor.
--
-- Supabase queda como fuente de verdad para:
--   1) Usuarios autorizados para iniciar sesión en Cruces GLM.
--   2) Permiso para Agregar / Editar / Eliminar formularios.
--   3) Datos de todos los formularios/cruces del Hub.
--   4) Sumatorias globales: formularios creados, aperturas y logueos.
--   5) Métricas por formulario y por usuario.
--   6) Historial de eventos.
--   7) Consultas y mutaciones mediante RPC; el frontend no necesita acceso
--      directo a las tablas.
--
-- IMPORTANTE:
-- Google/Supabase puede completar el OAuth, pero Cruces GLM consulta
-- cruces_glm_get_my_access() inmediatamente. Si is_allowed = false o el correo
-- no existe en cruces_glm_permissions, la app cierra esa sesión y no permite
-- entrar. Todas las RPC de datos vuelven a validar el acceso en servidor.
-- ============================================================================

begin;

-- --------------------------------------------------------------------------
-- 1. ACCESOS / PERMISOS
-- --------------------------------------------------------------------------

create table if not exists public.cruces_glm_permissions (
  email text primary key,
  display_name text,
  is_allowed boolean not null default true,
  can_manage_forms boolean not null default false,
  updated_at timestamptz not null default now(),
  constraint cruces_glm_permissions_email_lowercase check (email = lower(email))
);

-- Compatibilidad con versiones anteriores del script.
alter table public.cruces_glm_permissions
  add column if not exists display_name text;
alter table public.cruces_glm_permissions
  add column if not exists is_allowed boolean not null default true;
alter table public.cruces_glm_permissions
  add column if not exists can_manage_forms boolean not null default false;
alter table public.cruces_glm_permissions
  add column if not exists updated_at timestamptz not null default now();

alter table public.cruces_glm_permissions enable row level security;

create or replace function public.cruces_glm_set_updated_at()
returns trigger
language plpgsql
as $$
begin
  new.updated_at = now();
  return new;
end;
$$;

drop trigger if exists cruces_glm_permissions_set_updated_at
  on public.cruces_glm_permissions;
create trigger cruces_glm_permissions_set_updated_at
before update on public.cruces_glm_permissions
for each row execute function public.cruces_glm_set_updated_at();

-- Lista inicial autorizada. Solo Isaac administra formularios inicialmente.
-- ON CONFLICT preserva is_allowed/can_manage_forms para no deshacer cambios
-- manuales posteriores si actualizas solamente nombres.
insert into public.cruces_glm_permissions (
  email,
  display_name,
  is_allowed,
  can_manage_forms
)
values
  ('mgomez@gomezleemarketing.com', 'Máximo Gómez', true, false),
  ('iaracena@gomezleemarketing.com', 'Isaac Aracena', true, true),
  ('jgomez@gomezleemarketing.com', 'José Leopoldo Gómez', true, false),
  ('lmatos@gomezleemarketing.com', 'Luis Matos', true, false),
  ('ymadera@gomezleemarketing.com', 'Yanelly Madera', true, false),
  ('iherrera@gomezleemarketing.com', 'Iveth Herrera', true, false),
  ('msoto@gomezleemarketing.com', 'Mati Soto', true, false),
  ('vparamo@gomezleemarketing.com', 'Viviana Páramo', true, false),
  ('asrodriguez@gomezleemarketing.com', 'Ada Rodríguez', true, false),
  ('administrativonicaragua@gomezleemarketing.com', 'Estefani Dayana Orozco Dávila', true, false),
  ('administrativo@gomezleemarketing.com', 'Seyling Zambrana', true, false),
  ('adminregional@gomezleemarketing.com', 'Liliana Benítez', true, false)
on conflict (email) do update
set display_name = excluded.display_name;

-- --------------------------------------------------------------------------
-- 2. FORMULARIOS / CRUCES — FUENTE DE VERDAD
-- --------------------------------------------------------------------------

create table if not exists public.cruces_glm_forms (
  id text primary key,
  nombre text not null,
  descripcion text not null,
  categoria text not null,
  url text not null,
  activo boolean not null default true,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now(),
  created_by text,
  updated_by text,
  constraint cruces_glm_forms_categoria_check
    check (categoria in ('Seguridad Social', 'IR', 'Reportes')),
  constraint cruces_glm_forms_nombre_not_blank check (length(trim(nombre)) > 0),
  constraint cruces_glm_forms_descripcion_not_blank check (length(trim(descripcion)) > 0),
  constraint cruces_glm_forms_url_not_blank check (length(trim(url)) > 0)
);

create index if not exists cruces_glm_forms_categoria_idx
  on public.cruces_glm_forms (categoria, nombre);
create index if not exists cruces_glm_forms_activo_idx
  on public.cruces_glm_forms (activo, categoria);

alter table public.cruces_glm_forms enable row level security;

drop trigger if exists cruces_glm_forms_set_updated_at
  on public.cruces_glm_forms;
create trigger cruces_glm_forms_set_updated_at
before update on public.cruces_glm_forms
for each row execute function public.cruces_glm_set_updated_at();

-- --------------------------------------------------------------------------
-- 3. MÉTRICAS GLOBALES
-- --------------------------------------------------------------------------

create table if not exists public.cruces_glm_metrics_summary (
  id smallint primary key default 1,
  total_formularios_colocados bigint not null default 0 check (total_formularios_colocados >= 0),
  total_formularios_abiertos bigint not null default 0 check (total_formularios_abiertos >= 0),
  total_logueos bigint not null default 0 check (total_logueos >= 0),
  updated_at timestamptz not null default now(),
  constraint cruces_glm_metrics_summary_single_row check (id = 1)
);

insert into public.cruces_glm_metrics_summary (id)
values (1)
on conflict (id) do nothing;

alter table public.cruces_glm_metrics_summary enable row level security;

-- --------------------------------------------------------------------------
-- 4. MÉTRICAS POR FORMULARIO
-- --------------------------------------------------------------------------

create table if not exists public.cruces_glm_form_metrics (
  form_id text primary key,
  form_name text not null,
  category text,
  total_publicaciones bigint not null default 1 check (total_publicaciones >= 0),
  total_aperturas bigint not null default 0 check (total_aperturas >= 0),
  first_published_at timestamptz not null default now(),
  last_published_at timestamptz not null default now(),
  last_opened_at timestamptz
);

alter table public.cruces_glm_form_metrics enable row level security;

-- --------------------------------------------------------------------------
-- 5. MÉTRICAS POR USUARIO
-- --------------------------------------------------------------------------

create table if not exists public.cruces_glm_user_metrics (
  email text primary key,
  total_logueos bigint not null default 0 check (total_logueos >= 0),
  total_aperturas bigint not null default 0 check (total_aperturas >= 0),
  last_login_at timestamptz,
  last_opened_at timestamptz,
  constraint cruces_glm_user_metrics_email_lowercase check (email = lower(email))
);

alter table public.cruces_glm_user_metrics enable row level security;

-- --------------------------------------------------------------------------
-- 6. HISTORIAL DE EVENTOS
-- --------------------------------------------------------------------------

create table if not exists public.cruces_glm_metric_events (
  id bigint generated by default as identity primary key,
  event_type text not null check (event_type in ('login', 'form_created', 'form_opened')),
  user_email text not null,
  form_id text,
  form_name text,
  category text,
  created_at timestamptz not null default now()
);

create index if not exists cruces_glm_metric_events_type_idx
  on public.cruces_glm_metric_events (event_type, created_at desc);
create index if not exists cruces_glm_metric_events_user_idx
  on public.cruces_glm_metric_events (user_email, created_at desc);
create index if not exists cruces_glm_metric_events_form_idx
  on public.cruces_glm_metric_events (form_id, created_at desc);

alter table public.cruces_glm_metric_events enable row level security;

-- --------------------------------------------------------------------------
-- 7. SEGURIDAD BASE — SIN ACCESO DIRECTO DESDE EL FRONTEND
-- --------------------------------------------------------------------------
-- El navegador usa exclusivamente RPCs SECURITY DEFINER. Esto evita depender
-- de filtros construidos por el cliente para permisos o CRUD.

revoke all on table public.cruces_glm_permissions from anon, authenticated;
revoke all on table public.cruces_glm_forms from anon, authenticated;
revoke all on table public.cruces_glm_metrics_summary from anon, authenticated;
revoke all on table public.cruces_glm_form_metrics from anon, authenticated;
revoke all on table public.cruces_glm_user_metrics from anon, authenticated;
revoke all on table public.cruces_glm_metric_events from anon, authenticated;

-- Quitar policies antiguas conocidas; el acceso normal será solo vía RPC.
drop policy if exists "Cruces GLM - leer permiso propio"
  on public.cruces_glm_permissions;
drop policy if exists "Cruces GLM - administradores leen resumen"
  on public.cruces_glm_metrics_summary;
drop policy if exists "Cruces GLM - administradores leen metricas formularios"
  on public.cruces_glm_form_metrics;
drop policy if exists "Cruces GLM - administradores leen metricas usuarios"
  on public.cruces_glm_user_metrics;
drop policy if exists "Cruces GLM - administradores leen eventos"
  on public.cruces_glm_metric_events;

-- --------------------------------------------------------------------------
-- 8. HELPERS DE AUTORIZACIÓN
-- --------------------------------------------------------------------------

create or replace function public.cruces_glm_current_email()
returns text
language sql
stable
as $$
  select lower(coalesce(auth.jwt() ->> 'email', ''));
$$;

create or replace function public.cruces_glm_is_allowed()
returns boolean
language sql
stable
security definer
set search_path = public
as $$
  select exists (
    select 1
    from public.cruces_glm_permissions p
    where p.email = public.cruces_glm_current_email()
      and p.is_allowed = true
  );
$$;

create or replace function public.cruces_glm_can_manage_forms()
returns boolean
language sql
stable
security definer
set search_path = public
as $$
  select exists (
    select 1
    from public.cruces_glm_permissions p
    where p.email = public.cruces_glm_current_email()
      and p.is_allowed = true
      and p.can_manage_forms = true
  );
$$;

revoke all on function public.cruces_glm_current_email() from public;
revoke all on function public.cruces_glm_is_allowed() from public;
revoke all on function public.cruces_glm_can_manage_forms() from public;

-- --------------------------------------------------------------------------
-- 9. RPC — ACCESO DEL USUARIO ACTUAL
-- --------------------------------------------------------------------------
-- Esta es la fuente de verdad del login de Cruces GLM. No existe allowlist
-- hardcodeada en el frontend.

create or replace function public.cruces_glm_get_my_access()
returns table (
  allowed boolean,
  can_manage_forms boolean,
  display_name text
)
language plpgsql
stable
security definer
set search_path = public
as $$
declare
  v_email text := public.cruces_glm_current_email();
begin
  return query
  select
    coalesce(p.is_allowed, false) as allowed,
    (coalesce(p.is_allowed, false) and coalesce(p.can_manage_forms, false)) as can_manage_forms,
    p.display_name
  from (select v_email as email) current_user_email
  left join public.cruces_glm_permissions p
    on p.email = current_user_email.email;
end;
$$;

revoke all on function public.cruces_glm_get_my_access() from public;
grant execute on function public.cruces_glm_get_my_access() to authenticated;

-- --------------------------------------------------------------------------
-- 10. RPC — LISTAR FORMULARIOS
-- --------------------------------------------------------------------------

create or replace function public.cruces_glm_get_forms()
returns table (
  id text,
  nombre text,
  descripcion text,
  categoria text,
  url text,
  activo boolean,
  created_at timestamptz,
  updated_at timestamptz
)
language plpgsql
stable
security definer
set search_path = public
as $$
begin
  if not public.cruces_glm_is_allowed() then
    raise exception 'Usuario no autorizado para Cruces GLM';
  end if;

  return query
  select
    f.id,
    f.nombre,
    f.descripcion,
    f.categoria,
    f.url,
    f.activo,
    f.created_at,
    f.updated_at
  from public.cruces_glm_forms f
  order by f.nombre asc;
end;
$$;

revoke all on function public.cruces_glm_get_forms() from public;
grant execute on function public.cruces_glm_get_forms() to authenticated;

-- --------------------------------------------------------------------------
-- 11. RPC — CONSULTAR UN FORMULARIO
-- --------------------------------------------------------------------------

create or replace function public.cruces_glm_get_form(p_form_id text)
returns table (
  id text,
  nombre text,
  descripcion text,
  categoria text,
  url text,
  activo boolean,
  created_at timestamptz,
  updated_at timestamptz
)
language plpgsql
stable
security definer
set search_path = public
as $$
begin
  if not public.cruces_glm_is_allowed() then
    raise exception 'Usuario no autorizado para Cruces GLM';
  end if;

  return query
  select
    f.id,
    f.nombre,
    f.descripcion,
    f.categoria,
    f.url,
    f.activo,
    f.created_at,
    f.updated_at
  from public.cruces_glm_forms f
  where f.id = trim(coalesce(p_form_id, ''))
  limit 1;
end;
$$;

revoke all on function public.cruces_glm_get_form(text) from public;
grant execute on function public.cruces_glm_get_form(text) to authenticated;

-- --------------------------------------------------------------------------
-- 12. RPC — CREAR / EDITAR FORMULARIO
-- --------------------------------------------------------------------------
-- Registra total_formularios_colocados únicamente cuando el ID no existía.
-- Editar un formulario no incrementa esa sumatoria.

drop function if exists public.cruces_glm_record_form_created(text, text, text);

create or replace function public.cruces_glm_save_form(
  p_form_id text,
  p_nombre text,
  p_descripcion text,
  p_categoria text,
  p_url text,
  p_activo boolean
)
returns table (
  id text,
  nombre text,
  descripcion text,
  categoria text,
  url text,
  activo boolean,
  created_at timestamptz,
  updated_at timestamptz
)
language plpgsql
security definer
set search_path = public
as $$
declare
  v_email text := public.cruces_glm_current_email();
  v_id text := trim(coalesce(p_form_id, ''));
  v_nombre text := trim(coalesce(p_nombre, ''));
  v_descripcion text := trim(coalesce(p_descripcion, ''));
  v_categoria text := trim(coalesce(p_categoria, ''));
  v_url text := trim(coalesce(p_url, ''));
  v_activo boolean := coalesce(p_activo, false);
  v_existed boolean;
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para administrar formularios';
  end if;

  if v_id = '' or v_nombre = '' or v_descripcion = '' or v_categoria = '' or v_url = '' then
    raise exception 'Todos los campos del formulario son obligatorios';
  end if;

  if v_categoria not in ('Seguridad Social', 'IR', 'Reportes') then
    raise exception 'Categoría no válida';
  end if;

  if v_url !~* '^https?://' then
    raise exception 'La URL debe comenzar con http:// o https://';
  end if;

  select exists (
    select 1 from public.cruces_glm_forms f where f.id = v_id
  ) into v_existed;

  insert into public.cruces_glm_forms (
    id,
    nombre,
    descripcion,
    categoria,
    url,
    activo,
    created_by,
    updated_by
  )
  values (
    v_id,
    v_nombre,
    v_descripcion,
    v_categoria,
    v_url,
    v_activo,
    v_email,
    v_email
  )
  on conflict (id) do update
  set nombre = excluded.nombre,
      descripcion = excluded.descripcion,
      categoria = excluded.categoria,
      url = excluded.url,
      activo = excluded.activo,
      updated_by = excluded.updated_by;

  if not v_existed then
    insert into public.cruces_glm_metrics_summary (
      id,
      total_formularios_colocados,
      total_formularios_abiertos,
      total_logueos,
      updated_at
    )
    values (1, 1, 0, 0, now())
    on conflict (id) do update
    set total_formularios_colocados = public.cruces_glm_metrics_summary.total_formularios_colocados + 1,
        updated_at = now();

    insert into public.cruces_glm_form_metrics (
      form_id,
      form_name,
      category,
      total_publicaciones,
      total_aperturas,
      first_published_at,
      last_published_at
    )
    values (v_id, v_nombre, v_categoria, 1, 0, now(), now())
    on conflict (form_id) do update
    set form_name = excluded.form_name,
        category = excluded.category,
        total_publicaciones = public.cruces_glm_form_metrics.total_publicaciones + 1,
        last_published_at = now();

    insert into public.cruces_glm_metric_events (
      event_type,
      user_email,
      form_id,
      form_name,
      category
    )
    values ('form_created', v_email, v_id, v_nombre, v_categoria);
  else
    update public.cruces_glm_form_metrics
    set form_name = v_nombre,
        category = v_categoria
    where form_id = v_id;
  end if;

  return query
  select
    f.id,
    f.nombre,
    f.descripcion,
    f.categoria,
    f.url,
    f.activo,
    f.created_at,
    f.updated_at
  from public.cruces_glm_forms f
  where f.id = v_id;
end;
$$;

revoke all on function public.cruces_glm_save_form(text, text, text, text, text, boolean) from public;
grant execute on function public.cruces_glm_save_form(text, text, text, text, text, boolean) to authenticated;

-- --------------------------------------------------------------------------
-- 13. RPC — ELIMINAR FORMULARIO
-- --------------------------------------------------------------------------

create or replace function public.cruces_glm_delete_form(p_form_id text)
returns boolean
language plpgsql
security definer
set search_path = public
as $$
declare
  v_id text := trim(coalesce(p_form_id, ''));
  v_deleted_count integer;
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para administrar formularios';
  end if;

  delete from public.cruces_glm_forms f
  where f.id = v_id;

  get diagnostics v_deleted_count = row_count;
  return v_deleted_count > 0;
end;
$$;

revoke all on function public.cruces_glm_delete_form(text) from public;
grant execute on function public.cruces_glm_delete_form(text) to authenticated;

-- --------------------------------------------------------------------------
-- 14. RPC — REGISTRAR LOGIN
-- --------------------------------------------------------------------------

create or replace function public.cruces_glm_record_login()
returns void
language plpgsql
security definer
set search_path = public
as $$
declare
  v_email text := public.cruces_glm_current_email();
begin
  if not public.cruces_glm_is_allowed() then
    raise exception 'Usuario no autorizado para Cruces GLM';
  end if;

  insert into public.cruces_glm_metrics_summary (
    id,
    total_formularios_colocados,
    total_formularios_abiertos,
    total_logueos,
    updated_at
  )
  values (1, 0, 0, 1, now())
  on conflict (id) do update
  set total_logueos = public.cruces_glm_metrics_summary.total_logueos + 1,
      updated_at = now();

  insert into public.cruces_glm_user_metrics (
    email,
    total_logueos,
    total_aperturas,
    last_login_at
  )
  values (v_email, 1, 0, now())
  on conflict (email) do update
  set total_logueos = public.cruces_glm_user_metrics.total_logueos + 1,
      last_login_at = now();

  insert into public.cruces_glm_metric_events (event_type, user_email)
  values ('login', v_email);
end;
$$;

revoke all on function public.cruces_glm_record_login() from public;
grant execute on function public.cruces_glm_record_login() to authenticated;

-- --------------------------------------------------------------------------
-- 15. RPC — REGISTRAR APERTURA
-- --------------------------------------------------------------------------
-- Solo recibe el ID. Nombre/categoría/estado salen de la tabla real para evitar
-- manipulación desde el navegador. Un formulario inactivo no se contabiliza.

drop function if exists public.cruces_glm_record_form_open(text, text, text);

create or replace function public.cruces_glm_record_form_open(p_form_id text)
returns void
language plpgsql
security definer
set search_path = public
as $$
declare
  v_email text := public.cruces_glm_current_email();
  v_form_id text := trim(coalesce(p_form_id, ''));
  v_form_name text;
  v_category text;
  v_active boolean;
begin
  if not public.cruces_glm_is_allowed() then
    raise exception 'Usuario no autorizado para Cruces GLM';
  end if;

  select f.nombre, f.categoria, f.activo
    into v_form_name, v_category, v_active
  from public.cruces_glm_forms f
  where f.id = v_form_id;

  if not found then
    raise exception 'Formulario no encontrado';
  end if;

  if not v_active then
    raise exception 'Formulario no disponible';
  end if;

  insert into public.cruces_glm_metrics_summary (
    id,
    total_formularios_colocados,
    total_formularios_abiertos,
    total_logueos,
    updated_at
  )
  values (1, 0, 1, 0, now())
  on conflict (id) do update
  set total_formularios_abiertos = public.cruces_glm_metrics_summary.total_formularios_abiertos + 1,
      updated_at = now();

  insert into public.cruces_glm_user_metrics (
    email,
    total_logueos,
    total_aperturas,
    last_opened_at
  )
  values (v_email, 0, 1, now())
  on conflict (email) do update
  set total_aperturas = public.cruces_glm_user_metrics.total_aperturas + 1,
      last_opened_at = now();

  insert into public.cruces_glm_form_metrics (
    form_id,
    form_name,
    category,
    total_publicaciones,
    total_aperturas,
    first_published_at,
    last_published_at,
    last_opened_at
  )
  values (v_form_id, v_form_name, v_category, 0, 1, now(), now(), now())
  on conflict (form_id) do update
  set form_name = excluded.form_name,
      category = excluded.category,
      total_aperturas = public.cruces_glm_form_metrics.total_aperturas + 1,
      last_opened_at = now();

  insert into public.cruces_glm_metric_events (
    event_type,
    user_email,
    form_id,
    form_name,
    category
  )
  values ('form_opened', v_email, v_form_id, v_form_name, v_category);
end;
$$;

revoke all on function public.cruces_glm_record_form_open(text) from public;
grant execute on function public.cruces_glm_record_form_open(text) to authenticated;

-- --------------------------------------------------------------------------
-- 16. RPC — CONSULTAS DE MÉTRICAS PARA FUTURO DASHBOARD
-- --------------------------------------------------------------------------

create or replace function public.cruces_glm_get_metrics_summary()
returns table (
  total_formularios_colocados bigint,
  total_formularios_abiertos bigint,
  total_logueos bigint,
  updated_at timestamptz
)
language plpgsql
stable
security definer
set search_path = public
as $$
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para consultar métricas';
  end if;

  return query
  select
    m.total_formularios_colocados,
    m.total_formularios_abiertos,
    m.total_logueos,
    m.updated_at
  from public.cruces_glm_metrics_summary m
  where m.id = 1;
end;
$$;

create or replace function public.cruces_glm_get_form_metrics()
returns table (
  form_id text,
  form_name text,
  category text,
  total_publicaciones bigint,
  total_aperturas bigint,
  first_published_at timestamptz,
  last_published_at timestamptz,
  last_opened_at timestamptz
)
language plpgsql
stable
security definer
set search_path = public
as $$
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para consultar métricas';
  end if;

  return query
  select
    m.form_id,
    m.form_name,
    m.category,
    m.total_publicaciones,
    m.total_aperturas,
    m.first_published_at,
    m.last_published_at,
    m.last_opened_at
  from public.cruces_glm_form_metrics m
  order by m.total_aperturas desc, m.form_name asc;
end;
$$;

create or replace function public.cruces_glm_get_user_metrics()
returns table (
  email text,
  total_logueos bigint,
  total_aperturas bigint,
  last_login_at timestamptz,
  last_opened_at timestamptz
)
language plpgsql
stable
security definer
set search_path = public
as $$
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para consultar métricas';
  end if;

  return query
  select
    m.email,
    m.total_logueos,
    m.total_aperturas,
    m.last_login_at,
    m.last_opened_at
  from public.cruces_glm_user_metrics m
  order by m.total_logueos desc, m.email asc;
end;
$$;

create or replace function public.cruces_glm_get_recent_events(p_limit integer default 100)
returns table (
  id bigint,
  event_type text,
  user_email text,
  form_id text,
  form_name text,
  category text,
  created_at timestamptz
)
language plpgsql
stable
security definer
set search_path = public
as $$
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para consultar métricas';
  end if;

  return query
  select
    e.id,
    e.event_type,
    e.user_email,
    e.form_id,
    e.form_name,
    e.category,
    e.created_at
  from public.cruces_glm_metric_events e
  order by e.created_at desc
  limit least(greatest(coalesce(p_limit, 100), 1), 500);
end;
$$;

revoke all on function public.cruces_glm_get_metrics_summary() from public;
revoke all on function public.cruces_glm_get_form_metrics() from public;
revoke all on function public.cruces_glm_get_user_metrics() from public;
revoke all on function public.cruces_glm_get_recent_events(integer) from public;
grant execute on function public.cruces_glm_get_metrics_summary() to authenticated;
grant execute on function public.cruces_glm_get_form_metrics() to authenticated;
grant execute on function public.cruces_glm_get_user_metrics() to authenticated;
grant execute on function public.cruces_glm_get_recent_events(integer) to authenticated;

-- --------------------------------------------------------------------------
-- 17. RPC — ADMINISTRACIÓN DE ACCESOS
-- --------------------------------------------------------------------------
-- No hay UI para esto todavía, pero queda listo para una futura pantalla.
-- Hoy puedes administrar cruces_glm_permissions directamente en Table Editor.

create or replace function public.cruces_glm_admin_get_access_list()
returns table (
  email text,
  display_name text,
  is_allowed boolean,
  can_manage_forms boolean,
  updated_at timestamptz
)
language plpgsql
stable
security definer
set search_path = public
as $$
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para administrar accesos';
  end if;

  return query
  select
    p.email,
    p.display_name,
    p.is_allowed,
    p.can_manage_forms,
    p.updated_at
  from public.cruces_glm_permissions p
  order by p.display_name nulls last, p.email;
end;
$$;

create or replace function public.cruces_glm_admin_save_access(
  p_email text,
  p_display_name text,
  p_is_allowed boolean,
  p_can_manage_forms boolean
)
returns void
language plpgsql
security definer
set search_path = public
as $$
declare
  v_email text := lower(trim(coalesce(p_email, '')));
  v_name text := nullif(trim(coalesce(p_display_name, '')), '');
begin
  if not public.cruces_glm_can_manage_forms() then
    raise exception 'Usuario sin permiso para administrar accesos';
  end if;

  if v_email = '' or position('@' in v_email) <= 1 then
    raise exception 'Correo no válido';
  end if;

  insert into public.cruces_glm_permissions (
    email,
    display_name,
    is_allowed,
    can_manage_forms
  )
  values (
    v_email,
    v_name,
    coalesce(p_is_allowed, false),
    coalesce(p_can_manage_forms, false)
  )
  on conflict (email) do update
  set display_name = excluded.display_name,
      is_allowed = excluded.is_allowed,
      can_manage_forms = excluded.can_manage_forms;
end;
$$;

revoke all on function public.cruces_glm_admin_get_access_list() from public;
revoke all on function public.cruces_glm_admin_save_access(text, text, boolean, boolean) from public;
grant execute on function public.cruces_glm_admin_get_access_list() to authenticated;
grant execute on function public.cruces_glm_admin_save_access(text, text, boolean, boolean) to authenticated;

commit;

-- ============================================================================
-- ADMINISTRACIÓN RÁPIDA DESDE SQL EDITOR / TABLE EDITOR
-- ============================================================================
-- Dar acceso a Cruces GLM:
-- update public.cruces_glm_permissions
-- set is_allowed = true
-- where email = 'correo@gomezleemarketing.com';
--
-- Quitar acceso a Cruces GLM sin borrar historial:
-- update public.cruces_glm_permissions
-- set is_allowed = false
-- where email = 'correo@gomezleemarketing.com';
--
-- Dar permiso de Agregar / Editar / Eliminar:
-- update public.cruces_glm_permissions
-- set can_manage_forms = true
-- where email = 'correo@gomezleemarketing.com';
--
-- Quitar permiso de administración:
-- update public.cruces_glm_permissions
-- set can_manage_forms = false
-- where email = 'correo@gomezleemarketing.com';
--
-- Formularios actualmente guardados:
-- select * from public.cruces_glm_forms order by nombre;
--
-- Métricas globales:
-- select * from public.cruces_glm_metrics_summary;
--
-- Métricas por formulario:
-- select * from public.cruces_glm_form_metrics order by total_aperturas desc;
--
-- Métricas por usuario:
-- select * from public.cruces_glm_user_metrics order by total_logueos desc;
--
-- Eventos recientes:
-- select * from public.cruces_glm_metric_events order by created_at desc limit 100;
-- ============================================================================
