create table profiles (
    user_id uuid primary key references auth.users(id) on delete cascade,
    user_type text not null check (user_type in ('brand', 'creator', 'admin'))
);
alter table profiles enable row level security;
create policy profiles_everyone_select
    on profiles for select
    to authenticated, anon
    using (true);
create policy profiles_user_update
    on profiles for update
    using ( (select auth.uid()) = user_id );

create table brands (
    user_id uuid primary key references profiles(user_id) on delete cascade,
    company_name text not null,
    website text not null
);
alter table brands enable row level security;
create policy brands_everyone_select
    on brands for select
    to authenticated, anon
    using (true);
create policy brands_user_update
    on brands for update
    using ( (select auth.uid()) = user_id );

create table creators (
    user_id uuid primary key references profiles(user_id) on delete cascade,
    nickname text not null,
    bio text,
    social_links jsonb
);
alter table creators enable row level security;
create policy creators_everyone_select
    on creators for select
    to authenticated, anon
    using (true);
create policy creators_user_update
    on creators for update
    using ( (select auth.uid()) = user_id );


create table admins (
    user_id uuid primary key references profiles(user_id) on delete cascade
);
alter table admins enable row level security;
create policy admins_everyone_select
    on admins for select
    to authenticated, anon
    using (true);
create policy admins_user_update
    on admins for update
    using ( (select auth.uid()) = user_id );


-- based on raw_user_meta_data, create a profile and subprofile for new users
create function public.handle_new_user()
    returns trigger
    language plpgsql
    security definer set search_path = ''
as $$
declare
    user_type text;
begin
    user_type := new.raw_user_meta_data ->> 'user_type';
    if user_type is null or trim(user_type) = '' then
        raise exception 'Missing required user_type in raw_user_meta_data';
    end if;
    insert into profiles (user_id, user_type) values (new.id, new.raw_user_meta_data ->> 'user_type');
    if user_type = 'brand' then
        insert into brands (user_id, company_name, website)
        values (new.id,
                new.raw_user_meta_data ->> 'company_name',
                new.raw_user_meta_data ->> 'website');
    elsif user_type = 'creator' then
        insert into creators (user_id, nickname, bio, social_links)
        values (new.id,
                new.raw_user_meta_data ->> 'nickname',
                new.raw_user_meta_data ->> 'bio',
                new.raw_user_meta_data ->> 'social_links');
    elsif user_type = 'admin' then
        insert into admins (user_id) values (new.id);
    end if;
    return new;
end;
$$;

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

-- keep validation on subprofiles
create or replace function public.enforce_profile_type(user_id uuid, expected_type text)
    returns void
    language plpgsql
    security definer set search_path = ''
as $$
declare
    actual_type text;
begin
    select user_type into actual_type
    from profiles where user_id = user_id;

    if actual_type is null then
        raise exception 'profile not found for id: %', user_id;
    end if;

    if actual_type <> expected_type then
        raise exception 'user_type mismatch: expected %, got %', expected_type, actual_type;
    end if;
end;
$$;

create or replace function public.check_brand_user_type()
    returns trigger
    language plpgsql
    security definer set search_path = ''
as $$ begin
    perform public.enforce_profile_type(new.user_id, 'brand');
    return new;
end; $$;

create or replace function public.check_creator_user_type()
    returns trigger
    language plpgsql
    security definer set search_path = ''
as $$ begin
    perform public.enforce_profile_type(new.user_id, 'creator');
    return new;
end; $$;

create or replace function public.check_admin_user_type()
    returns trigger
    language plpgsql
    security definer set search_path = ''
as $$ begin
    perform public.enforce_profile_type(new.user_id, 'admin');
    return new;
end; $$;

create trigger check_brands_user_type
    before insert or update
    on brands
    for each row
execute function public.check_brand_user_type();

create trigger check_creators_user_type
    before insert or update
    on creators
    for each row
execute function public.check_creator_user_type();

create trigger check_admins_user_type
    before insert or update
    on admins
    for each row
execute function public.check_admin_user_type();
