-- 0010: Allow trusted server-side internal Auth user creation
-- Run after: supabase/migrations/0009_lock_registration_after_first_admin.sql

create schema if not exists neta_internal;

create table if not exists neta_internal.internal_auth_creations (
  id uuid default uuid_generate_v4() primary key,
  email text not null,
  reason text default 'internal'::text not null,
  created_at timestamp with time zone default timezone('utc'::text, now()) not null,
  expires_at timestamp with time zone default (timezone('utc'::text, now()) + interval '2 minutes') not null
);

create index if not exists internal_auth_creations_email_idx
  on neta_internal.internal_auth_creations (lower(email));

revoke all on schema neta_internal from public;
revoke all on all tables in schema neta_internal from public;

create or replace function public.neta_current_jwt_role()
returns text
language sql
stable
as $$
  select coalesce(
    nullif(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role', ''),
    nullif(current_setting('request.jwt.claim.role', true), ''),
    ''
  );
$$;

revoke all on function public.neta_current_jwt_role() from public;
grant execute on function public.neta_current_jwt_role() to anon;
grant execute on function public.neta_current_jwt_role() to authenticated;
grant execute on function public.neta_current_jwt_role() to service_role;

create or replace function public.request_internal_auth_creation(
  target_email text,
  target_reason text default 'internal'
)
returns void
language plpgsql
security definer
set search_path = public, neta_internal
as $$
begin
  if public.neta_current_jwt_role() <> 'service_role' then
    raise exception 'Only service role can request internal auth creation.';
  end if;

  if target_email is null or btrim(target_email) = '' then
    raise exception 'target_email is required.';
  end if;

  delete from neta_internal.internal_auth_creations
  where expires_at <= timezone('utc'::text, now())
    or lower(email) = lower(btrim(target_email));

  insert into neta_internal.internal_auth_creations (email, reason)
  values (btrim(target_email), coalesce(nullif(btrim(target_reason), ''), 'internal'));
end;
$$;

revoke all on function public.request_internal_auth_creation(text, text) from public;
grant execute on function public.request_internal_auth_creation(text, text) to service_role;

create or replace function public.handle_new_user()
returns trigger
language plpgsql
security definer
set search_path = public, neta_internal
as $$
declare
  allowed_internal_creation boolean := false;
begin
  delete from neta_internal.internal_auth_creations
  where lower(email) = lower(new.email)
    and expires_at > timezone('utc'::text, now())
  returning true into allowed_internal_creation;

  allowed_internal_creation := coalesce(allowed_internal_creation, false);

  if exists (select 1 from public.profiles limit 1)
    and coalesce(new.raw_app_meta_data->>'internal_created', 'false') <> 'true'
    and not allowed_internal_creation then
    raise exception 'Registration is closed. The first admin account already exists.';
  end if;

  insert into public.profiles (id, first_name, last_name, avatar_url)
  values (new.id, '', '', '')
  on conflict (id) do nothing;

  return new;
end;
$$;

drop trigger if exists on_auth_user_created on auth.users;

create trigger on_auth_user_created
  after insert on auth.users
  for each row execute procedure public.handle_new_user();

notify pgrst, 'reload schema';
