-- Overlap prevention for reservations using btree_gist exclusion constraint
create extension if not exists btree_gist;

alter table public.reservations
  add constraint no_overlapping_reservations
  exclude using gist (
    boat_id with =,
    tstzrange(start_time, end_time, '[)') with &&
  );

-- Function: check member has required certs for a boat
create or replace function public.member_has_cert_for_boat(p_user_id uuid, p_boat_id uuid)
returns boolean
language sql
stable
security definer
set search_path = public
as $$
  select
    case
      when array_length(b.required_certs, 1) is null or array_length(b.required_certs, 1) = 0
        then true
      else
        coalesce(
          (select m.certifications @> b.required_certs
           from public.members m
           where m.user_id = p_user_id),
          false
        )
    end
  from public.boats b
  where b.id = p_boat_id;
$$;

-- Trigger: enforce cert check on reservation insert
create or replace function public.enforce_reservation_cert_check()
returns trigger
language plpgsql
security definer
set search_path = public
as $$
begin
  if not coalesce(public.member_has_cert_for_boat(new.user_id, new.boat_id), false) then
    raise exception 'Member does not have required certifications for this boat';
  end if;
  return new;
end;
$$;

create trigger check_reservation_certs
  before insert on public.reservations
  for each row execute function public.enforce_reservation_cert_check();

grant execute on function public.member_has_cert_for_boat(uuid, uuid) to authenticated;
