-- =============================================================================
-- MC Cars — Postgres bootstrap.
-- Creates the Supabase service roles that GoTrue / PostgREST / Storage expect,
-- installs required extensions, and sets up app schema + RLS + storage policies
-- + admin seed + sample fleet.
-- Runs once on first `docker compose up`.
-- =============================================================================

-- The Postgres connection is authenticated as role `supabase_admin` (POSTGRES_USER),
-- so we need it to be a superuser for the rest of this script to work. That is
-- handled by POSTGRES_USER=supabase_admin in compose.

create extension if not exists pgcrypto;
create extension if not exists "uuid-ossp";

-- Make the password from the shell wrapper available to the DO block below.
select set_config('mccars.pg_password', :'pg_password', false);

-- -----------------------------------------------------------------------------
-- Supabase service roles
-- -----------------------------------------------------------------------------
do $roles$
declare
    pw text := current_setting('mccars.pg_password', true);
begin
    if pw is null or pw = '' then
        raise exception 'mccars.pg_password is not set';
    end if;

    -- anon (used by PostgREST for unauthenticated requests)
    if not exists (select 1 from pg_roles where rolname = 'anon') then
        execute 'create role anon nologin noinherit';
    end if;

    -- authenticated (role the JWT "authenticated" maps to)
    if not exists (select 1 from pg_roles where rolname = 'authenticated') then
        execute 'create role authenticated nologin noinherit';
    end if;

    -- service_role (full access; never exposed to the browser)
    if not exists (select 1 from pg_roles where rolname = 'service_role') then
        execute 'create role service_role nologin noinherit bypassrls';
    end if;

    -- authenticator (PostgREST logs in as this and switches role per JWT)
    if not exists (select 1 from pg_roles where rolname = 'authenticator') then
        execute format('create role authenticator login noinherit password %L', pw);
    else
        execute format('alter role authenticator with login noinherit password %L', pw);
    end if;

    -- supabase_auth_admin (GoTrue logs in with this, needs schema auth)
    if not exists (select 1 from pg_roles where rolname = 'supabase_auth_admin') then
        execute format('create role supabase_auth_admin login createrole password %L', pw);
    else
        execute format('alter role supabase_auth_admin with login createrole password %L', pw);
    end if;

    -- supabase_storage_admin (Storage service logs in with this)
    if not exists (select 1 from pg_roles where rolname = 'supabase_storage_admin') then
        execute format('create role supabase_storage_admin login createrole password %L', pw);
    else
        execute format('alter role supabase_storage_admin with login createrole password %L', pw);
    end if;

    -- Let authenticator impersonate app roles.
    execute 'grant anon, authenticated, service_role to authenticator';

    -- Let storage_admin impersonate app roles (needed for RLS on storage.objects).
    execute 'grant anon, authenticated, service_role to supabase_storage_admin';
end
$roles$;

-- -----------------------------------------------------------------------------
-- Schemas for GoTrue / Storage (they create their own objects, but own schema)
-- -----------------------------------------------------------------------------
create schema if not exists auth    authorization supabase_auth_admin;
create schema if not exists storage authorization supabase_storage_admin;
create schema if not exists _realtime authorization postgres;

grant usage on schema auth      to service_role, authenticated, anon;
grant usage on schema storage   to service_role, authenticated, anon;
grant all   on schema _realtime to postgres;

-- Allow service admins to create/alter objects for their own migrations.
grant create, connect on database postgres to supabase_auth_admin, supabase_storage_admin;
grant all on schema auth    to supabase_auth_admin;
grant all on schema storage to supabase_storage_admin;

-- Storage-api's migration process expects to see public schema too.
grant usage, create on schema public to supabase_storage_admin, supabase_auth_admin;

-- -----------------------------------------------------------------------------
-- Application schema: public.vehicles
-- -----------------------------------------------------------------------------
create table if not exists public.vehicles (
    id               uuid primary key default gen_random_uuid(),
    brand            text        not null,
    model            text        not null,
    power_hp         integer     not null default 0,
    top_speed_kmh    integer     not null default 0,
    acceleration     text        not null default '',
    seats            integer     not null default 2,
    daily_price_eur  integer     not null default 0,
    location         text        not null default 'Steiermark (TBD)',
    description_de   text        not null default '',
    description_en   text        not null default '',
    photo_url        text        not null default '',
    photo_path       text,
    sort_order       integer     not null default 100,
    is_active        boolean     not null default true,
    created_at       timestamptz not null default now(),
    updated_at       timestamptz not null default now()
);

create index if not exists vehicles_active_sort_idx
    on public.vehicles (is_active, sort_order);

create or replace function public.tg_touch_updated_at() returns trigger
language plpgsql as $$
begin
    new.updated_at := now();
    return new;
end;
$$;

drop trigger if exists vehicles_touch on public.vehicles;
create trigger vehicles_touch
    before update on public.vehicles
    for each row execute function public.tg_touch_updated_at();

alter table public.vehicles enable row level security;

drop policy if exists "vehicles_public_read"   on public.vehicles;
drop policy if exists "vehicles_admin_read_all" on public.vehicles;
drop policy if exists "vehicles_admin_insert"  on public.vehicles;
drop policy if exists "vehicles_admin_update"  on public.vehicles;
drop policy if exists "vehicles_admin_delete"  on public.vehicles;

create policy "vehicles_public_read"
    on public.vehicles for select
    using (is_active = true);

create policy "vehicles_admin_read_all"
    on public.vehicles for select
    to authenticated using (true);

create policy "vehicles_admin_insert"
    on public.vehicles for insert
    to authenticated with check (true);

create policy "vehicles_admin_update"
    on public.vehicles for update
    to authenticated using (true) with check (true);

create policy "vehicles_admin_delete"
    on public.vehicles for delete
    to authenticated using (true);

grant select on public.vehicles to anon, authenticated;
grant insert, update, delete on public.vehicles to authenticated;
grant all on public.vehicles to service_role;

-- -----------------------------------------------------------------------------
-- Seed sample fleet (admin can replace any row / photo via the UI)
-- -----------------------------------------------------------------------------
insert into public.vehicles
    (brand, model, power_hp, top_speed_kmh, acceleration, seats,
     daily_price_eur, location, description_de, description_en, photo_url, sort_order)
values
    ('Ferrari','296 GTB', 830, 330, '2.9s', 2, 850, 'Steiermark (TBD)',
     'V6-Hybrid mit 830 PS, atemberaubendes Design und kompromisslose Performance auf Strasse und Rennstrecke.',
     'V6 hybrid with 830 hp, breathtaking design and uncompromising performance on road and track.',
     '/images/ferrari-main-car.png',
     10)
on conflict do nothing;
