-- Redemption-code management is an ordinary admin-console capability.
-- Keep actor verification, trusted request IDs and server-owned audit markers,
-- but do not reuse the narrower billing adjustment permission.

create or replace function public.require_admin_redemption_reason()
returns trigger
language plpgsql
set search_path = ''
as $$
declare
  v_reason text := nullif(btrim(current_setting('app.admin_redemption_reason', true)), '');
begin
  if new.action in ('redemption_code.create','redemption_code.update','redemption_code.revoke') then
    if v_reason is null or char_length(v_reason) > 500 then
      raise exception 'admin_reason_required' using errcode='22023';
    end if;
    new.permission_used := 'admin.access';
    new.reason := v_reason;
  end if;
  return new;
end;
$$;

revoke all on function public.require_admin_redemption_reason()
  from public, anon, authenticated, service_role;

create or replace function public.admin_create_redemption_codes(
  p_actor_user_id uuid,p_actor_email text,p_actor_role text,p_request_id text,p_codes jsonb,p_reason text
)
returns table(id uuid,code_mask text,credits integer,expires_at timestamptz,note text,created_at timestamptz,
  redeemed_by uuid,redeemed_email text,redeemed_at timestamptz,revoked_by uuid,revoked_at timestamptz)
language plpgsql security definer set search_path = ''
as $$
begin
  if not public.admin_has_permission(p_actor_user_id,'admin.access') then
    raise exception 'admin_permission_denied' using errcode='42501';
  end if;
  if char_length(btrim(coalesce(p_reason,''))) not between 1 and 500 then
    raise exception 'admin_reason_required' using errcode='22023';
  end if;
  perform set_config('app.admin_redemption_reason',btrim(p_reason),true);
  return query select * from public.admin_create_redemption_codes(
    p_actor_user_id,p_actor_email,p_actor_role,p_request_id,p_codes
  );
end;
$$;

create or replace function public.admin_update_redemption_code(
  p_actor_user_id uuid,p_actor_email text,p_actor_role text,p_request_id text,p_code_id uuid,
  p_set_note boolean,p_note text,p_set_expires_at boolean,p_expires_at timestamptz,p_reason text
)
returns table(id uuid,code_mask text,credits integer,expires_at timestamptz,note text,created_at timestamptz,
  redeemed_by uuid,redeemed_email text,redeemed_at timestamptz,revoked_by uuid,revoked_at timestamptz)
language plpgsql security definer set search_path = ''
as $$
begin
  if not public.admin_has_permission(p_actor_user_id,'admin.access') then
    raise exception 'admin_permission_denied' using errcode='42501';
  end if;
  if char_length(btrim(coalesce(p_reason,''))) not between 1 and 500 then
    raise exception 'admin_reason_required' using errcode='22023';
  end if;
  perform set_config('app.admin_redemption_reason',btrim(p_reason),true);
  return query select * from public.admin_update_redemption_code(
    p_actor_user_id,p_actor_email,p_actor_role,p_request_id,p_code_id,
    p_set_note,p_note,p_set_expires_at,p_expires_at
  );
end;
$$;

create or replace function public.admin_revoke_redemption_code(
  p_actor_user_id uuid,p_actor_email text,p_actor_role text,p_request_id text,p_code_id uuid,p_reason text
)
returns table(id uuid,code_mask text,credits integer,expires_at timestamptz,note text,created_at timestamptz,
  redeemed_by uuid,redeemed_email text,redeemed_at timestamptz,revoked_by uuid,revoked_at timestamptz)
language plpgsql security definer set search_path = ''
as $$
begin
  if not public.admin_has_permission(p_actor_user_id,'admin.access') then
    raise exception 'admin_permission_denied' using errcode='42501';
  end if;
  if char_length(btrim(coalesce(p_reason,''))) not between 1 and 500 then
    raise exception 'admin_reason_required' using errcode='22023';
  end if;
  perform set_config('app.admin_redemption_reason',btrim(p_reason),true);
  return query select * from public.admin_revoke_redemption_code(
    p_actor_user_id,p_actor_email,p_actor_role,p_request_id,p_code_id
  );
end;
$$;

revoke all on function public.admin_create_redemption_codes(uuid,text,text,text,jsonb,text),
  public.admin_update_redemption_code(uuid,text,text,text,uuid,boolean,text,boolean,timestamptz,text),
  public.admin_revoke_redemption_code(uuid,text,text,text,uuid,text)
  from public, anon, authenticated, service_role;

do $$
begin
  if exists(select 1 from pg_roles where rolname='admin_runtime') then
    grant execute on function public.admin_create_redemption_codes(uuid,text,text,text,jsonb,text),
      public.admin_update_redemption_code(uuid,text,text,text,uuid,boolean,text,boolean,timestamptz,text),
      public.admin_revoke_redemption_code(uuid,text,text,text,uuid,text)
      to admin_runtime;
  end if;
end
$$;
