-- OYS Borrow a Boat — Supabase Schema

-- ============================================================
-- TABLES
-- ============================================================

create table public.boats (
  id                uuid        primary key default gen_random_uuid(),
  name              text        not null,
  display_name      text,
  class             text,
  year              integer,
  img_src           text,
  icon_src          text,
  booking_available boolean     not null default true,
  required_certs    text[]      not null default '{}',
  max_passengers    integer     not null default 6,
  defects           jsonb       not null default '[]',
  -- defects shape: [{ type: string, severity: string, description: string, detail?: string }]
  created_at        timestamptz not null default now()
);

create table public.members (
  id              uuid        primary key default gen_random_uuid(),
  user_id         uuid        not null references auth.users(id) on delete cascade,
  first_name      text        not null default '',
  last_name       text        not null default '',
  email           text        not null,
  slack_id        text,
  certifications  text[]      not null default '{}',
  -- cert codes match boats.required_certs values (e.g. 'j27', 'capri25')
  role            text        not null default 'member'
                              check (role in ('member', 'skipper', 'admin', 'boatswain', 'volunteer', 'instructor')),
  created_at      timestamptz not null default now(),
  unique(user_id)
);

create table public.interval_templates (
  id          uuid        primary key default gen_random_uuid(),
  name        text        not null,
  time_tuples jsonb       not null default '[]',
  -- shape: [[startHHMM, endHHMM], ...] e.g. [["08:00","12:00"],["13:00","17:00"]]
  created_at  timestamptz not null default now()
);

create table public.intervals (
  id         uuid        primary key default gen_random_uuid(),
  boat_id    uuid        not null references public.boats(id) on delete cascade,
  start_time timestamptz not null,
  end_time   timestamptz not null,
  user_id    uuid        references auth.users(id) on delete set null,
  created_at timestamptz not null default now()
);

create index intervals_boat_id_idx on public.intervals(boat_id);
create index intervals_time_range_idx on public.intervals(start_time, end_time);

create table public.reservations (
  id          uuid        primary key default gen_random_uuid(),
  boat_id     uuid        not null references public.boats(id) on delete cascade,
  user_id     uuid        not null references auth.users(id) on delete cascade,
  start_time  timestamptz not null,
  end_time    timestamptz not null,
  status      text        not null default 'pending'
              check (status in ('pending', 'tentative', 'confirmed')),
  reason      text        not null default '',
  comment     text        not null default '',
  member_ids  text[]      not null default '{}',
  guest_ids   text[]      not null default '{}',
  created_at  timestamptz not null default now()
);

create index reservations_boat_id_idx on public.reservations(boat_id);
create index reservations_user_id_idx on public.reservations(user_id);
create index reservations_time_range_idx on public.reservations(start_time, end_time);

create table public.reference_docs (
  id         uuid        primary key default gen_random_uuid(),
  title      text        not null,
  category   text        not null,
  tags       text[]      not null default '{}',
  subtitle   text,
  content    text        not null,
  created_at timestamptz not null default now()
);

-- ============================================================
-- RLS
-- ============================================================

alter table public.boats enable row level security;
alter table public.members enable row level security;
alter table public.interval_templates enable row level security;
alter table public.intervals enable row level security;
alter table public.reservations enable row level security;
alter table public.reference_docs enable row level security;

-- boats
create policy "Authenticated users can read boats" on public.boats
  for select using (auth.role() = 'authenticated');
create policy "Admins can manage boats" on public.boats
  for all using (
    exists (
      select 1 from public.members
      where user_id = auth.uid() and role in ('admin', 'boatswain')
    )
  );

-- members
create policy "Users can read own member record" on public.members
  for select using (user_id = auth.uid());
create policy "Admins can read all members" on public.members
  for select using (
    exists (
      select 1 from public.members m2
      where m2.user_id = auth.uid() and m2.role in ('admin', 'boatswain', 'instructor')
    )
  );
create policy "Users can update own member record" on public.members
  for update using (user_id = auth.uid());
create policy "Admins can manage all members" on public.members
  for all using (
    exists (
      select 1 from public.members m2
      where m2.user_id = auth.uid() and m2.role = 'admin'
    )
  );

-- interval_templates
create policy "Authenticated users can read interval templates" on public.interval_templates
  for select using (auth.role() = 'authenticated');
create policy "Admins can manage interval templates" on public.interval_templates
  for all using (
    exists (
      select 1 from public.members
      where user_id = auth.uid() and role in ('admin', 'boatswain')
    )
  );

-- intervals
create policy "Authenticated users can read intervals" on public.intervals
  for select using (auth.role() = 'authenticated');
create policy "Admins can manage intervals" on public.intervals
  for all using (
    exists (
      select 1 from public.members
      where user_id = auth.uid() and role in ('admin', 'boatswain')
    )
  );

-- reservations
create policy "Users can read own reservations" on public.reservations
  for select using (user_id = auth.uid());
create policy "Admins can read all reservations" on public.reservations
  for select using (
    exists (
      select 1 from public.members
      where user_id = auth.uid() and role in ('admin', 'boatswain')
    )
  );
create policy "Authenticated users can read non-private reservation slots" on public.reservations
  for select using (auth.role() = 'authenticated');
create policy "Users can create own reservations" on public.reservations
  for insert with check (user_id = auth.uid());
create policy "Users can update own reservations" on public.reservations
  for update using (user_id = auth.uid());
create policy "Admins can manage all reservations" on public.reservations
  for all using (
    exists (
      select 1 from public.members
      where user_id = auth.uid() and role in ('admin', 'boatswain')
    )
  );

-- reference_docs
create policy "Authenticated users can read reference docs" on public.reference_docs
  for select using (auth.role() = 'authenticated');
create policy "Admins can manage reference docs" on public.reference_docs
  for all using (
    exists (
      select 1 from public.members
      where user_id = auth.uid() and role = 'admin'
    )
  );

-- ============================================================
-- TRIGGER: create member record on first sign-in
-- ============================================================

create or replace function public.handle_new_user()
returns trigger language plpgsql security definer as $$
begin
  insert into public.members (user_id, email)
  values (new.id, new.email)
  on conflict (user_id) do nothing;
  return new;
end;
$$;

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