-- Guest access still uses a real authenticated Supabase user. This keeps the
-- existing ownership checks, RLS policies, and multiplayer membership model.
-- Email accounts remain restricted to the allowlist.

create or replace function public.create_profile_for_allowlisted_user()
returns trigger
language plpgsql
security definer
set search_path = ''
as $$
declare
  v_is_anonymous boolean := coalesce(new.is_anonymous, false);
  v_display_name text;
begin
  if not v_is_anonymous and (
    new.email is null or not exists (
      select 1
      from public.allowlist
      where email = lower(btrim(new.email))
    )
  ) then
    raise exception using
      errcode = '42501',
      message = 'This email is not invited to the Dungeons & Ground alpha.';
  end if;

  v_display_name := case
    when v_is_anonymous then 'Guest ' || upper(substr(replace(new.id::text, '-', ''), 1, 6))
    else coalesce(nullif(btrim(new.raw_user_meta_data ->> 'display_name'), ''), 'Adventurer')
  end;

  insert into public.profiles(id, display_name)
  values (new.id, v_display_name)
  on conflict (id) do nothing;

  return new;
end;
$$;

revoke all on function public.create_profile_for_allowlisted_user() from public;

-- An anonymous account can be upgraded later. Recheck the allowlist on the
-- relevant auth.users transition so linking an email cannot bypass the alpha
-- gate. Unrelated token and metadata updates do not fire this trigger.
create or replace function public.enforce_alpha_email_allowlist()
returns trigger
language plpgsql
security definer
set search_path = ''
as $$
begin
  if not coalesce(new.is_anonymous, false) and (
    new.email is null or not exists (
      select 1
      from public.allowlist
      where email = lower(btrim(new.email))
    )
  ) then
    raise exception using
      errcode = '42501',
      message = 'This email is not invited to the Dungeons & Ground alpha.';
  end if;

  return new;
end;
$$;

revoke all on function public.enforce_alpha_email_allowlist() from public;

drop trigger if exists enforce_alpha_email_allowlist on auth.users;
create trigger enforce_alpha_email_allowlist
before update of email, is_anonymous on auth.users
for each row
when (
  old.email is distinct from new.email
  or old.is_anonymous is distinct from new.is_anonymous
)
execute function public.enforce_alpha_email_allowlist();

-- The schema may be installed after Auth users already exist. Backfill only
-- anonymous users and explicitly allowlisted email accounts; do not silently
-- enable unrelated accounts.
insert into public.profiles(id, display_name)
select
  auth_user.id,
  case
    when coalesce(auth_user.is_anonymous, false)
      then 'Guest ' || upper(substr(replace(auth_user.id::text, '-', ''), 1, 6))
    else coalesce(nullif(btrim(auth_user.raw_user_meta_data ->> 'display_name'), ''), 'Adventurer')
  end
from auth.users auth_user
where coalesce(auth_user.is_anonymous, false)
   or exists (
     select 1
     from public.allowlist
     where allowlist.email = lower(btrim(auth_user.email))
   )
on conflict (id) do nothing;

notify pgrst, 'reload schema';
