-- Corrections suite au linter de performance Supabase (get_advisors) :
-- 1. Wrap auth.uid() en (select auth.uid()) dans toutes les policies RLS
--    (évite une réévaluation par ligne — recommandation officielle Supabase).
-- 2. Index sur toutes les clés étrangères signalées.

-- ---- profiles ----
drop policy if exists "profiles_update_own" on public.profiles;
create policy "profiles_update_own"
  on public.profiles for update
  to authenticated
  using ((select auth.uid()) = id)
  with check ((select auth.uid()) = id);

-- ---- needs ----
drop policy if exists "needs_select" on public.needs;
create policy "needs_select"
  on public.needs for select
  using (status = 'open' or (select auth.uid()) = author_id);

drop policy if exists "needs_insert_own" on public.needs;
create policy "needs_insert_own"
  on public.needs for insert
  to authenticated
  with check ((select auth.uid()) = author_id);

drop policy if exists "needs_update_own" on public.needs;
create policy "needs_update_own"
  on public.needs for update
  to authenticated
  using ((select auth.uid()) = author_id)
  with check ((select auth.uid()) = author_id);

-- ---- need_images ----
drop policy if exists "need_images_select" on public.need_images;
create policy "need_images_select"
  on public.need_images for select
  using (
    exists (
      select 1 from public.needs n
      where n.id = need_id and (n.status = 'open' or (select auth.uid()) = n.author_id)
    )
  );

drop policy if exists "need_images_insert_own" on public.need_images;
create policy "need_images_insert_own"
  on public.need_images for insert
  to authenticated
  with check (
    exists (select 1 from public.needs n where n.id = need_id and n.author_id = (select auth.uid()))
  );

drop policy if exists "need_images_delete_own" on public.need_images;
create policy "need_images_delete_own"
  on public.need_images for delete
  to authenticated
  using (
    exists (select 1 from public.needs n where n.id = need_id and n.author_id = (select auth.uid()))
  );

-- ---- offers ----
drop policy if exists "offers_select" on public.offers;
create policy "offers_select"
  on public.offers for select
  to authenticated
  using (
    (select auth.uid()) = merchant_id
    or exists (select 1 from public.needs n where n.id = need_id and n.author_id = (select auth.uid()))
  );

drop policy if exists "offers_insert" on public.offers;
create policy "offers_insert"
  on public.offers for insert
  to authenticated
  with check (
    merchant_id = (select auth.uid())
    and exists (
      select 1 from public.needs n
      where n.id = need_id and n.status = 'open' and n.author_id <> (select auth.uid())
    )
  );

drop policy if exists "offers_update_own_pending" on public.offers;
create policy "offers_update_own_pending"
  on public.offers for update
  to authenticated
  using ((select auth.uid()) = merchant_id and status = 'pending')
  with check ((select auth.uid()) = merchant_id);

-- ---- offer_images ----
drop policy if exists "offer_images_select" on public.offer_images;
create policy "offer_images_select"
  on public.offer_images for select
  to authenticated
  using (
    exists (
      select 1 from public.offers o
      where o.id = offer_id
        and (
          o.merchant_id = (select auth.uid())
          or exists (select 1 from public.needs n where n.id = o.need_id and n.author_id = (select auth.uid()))
        )
    )
  );

drop policy if exists "offer_images_insert_own" on public.offer_images;
create policy "offer_images_insert_own"
  on public.offer_images for insert
  to authenticated
  with check (
    exists (select 1 from public.offers o where o.id = offer_id and o.merchant_id = (select auth.uid()))
  );

-- ---- conversations ----
drop policy if exists "conversations_select" on public.conversations;
create policy "conversations_select"
  on public.conversations for select
  to authenticated
  using ((select auth.uid()) = author_id or (select auth.uid()) = merchant_id);

-- ---- messages ----
drop policy if exists "messages_select" on public.messages;
create policy "messages_select"
  on public.messages for select
  to authenticated
  using (
    exists (
      select 1 from public.conversations c
      where c.id = conversation_id and ((select auth.uid()) = c.author_id or (select auth.uid()) = c.merchant_id)
    )
  );

drop policy if exists "messages_insert" on public.messages;
create policy "messages_insert"
  on public.messages for insert
  to authenticated
  with check (
    sender_id = (select auth.uid())
    and exists (
      select 1 from public.conversations c
      where c.id = conversation_id and ((select auth.uid()) = c.author_id or (select auth.uid()) = c.merchant_id)
    )
  );

-- ---- storage.objects (offer-images) ----
drop policy if exists "offer_images_bucket_read" on storage.objects;
create policy "offer_images_bucket_read"
  on storage.objects for select
  to authenticated
  using (
    bucket_id = 'offer-images'
    and exists (
      select 1
      from public.offer_images oi
      join public.offers o on o.id = oi.offer_id
      where oi.storage_path = storage.objects.name
        and (
          o.merchant_id = (select auth.uid())
          or exists (select 1 from public.needs n where n.id = o.need_id and n.author_id = (select auth.uid()))
        )
    )
  );

drop policy if exists "need_images_bucket_write" on storage.objects;
create policy "need_images_bucket_write"
  on storage.objects for insert
  to authenticated
  with check (
    bucket_id = 'need-images'
    and (storage.foldername(name))[1] = (select auth.uid())::text
  );

drop policy if exists "offer_images_bucket_write" on storage.objects;
create policy "offer_images_bucket_write"
  on storage.objects for insert
  to authenticated
  with check (
    bucket_id = 'offer-images'
    and (storage.foldername(name))[1] = (select auth.uid())::text
  );

-- ---- Index sur les clés étrangères ----
create index if not exists idx_needs_author_id on public.needs (author_id);
create index if not exists idx_needs_category_id on public.needs (category_id);
create index if not exists idx_needs_accepted_offer_id on public.needs (accepted_offer_id);
create index if not exists idx_need_images_need_id on public.need_images (need_id);
create index if not exists idx_offers_merchant_id on public.offers (merchant_id);
create index if not exists idx_offer_images_offer_id on public.offer_images (offer_id);
create index if not exists idx_conversations_need_id on public.conversations (need_id);
create index if not exists idx_conversations_author_id on public.conversations (author_id);
create index if not exists idx_conversations_merchant_id on public.conversations (merchant_id);
create index if not exists idx_messages_conversation_id on public.messages (conversation_id);
create index if not exists idx_messages_sender_id on public.messages (sender_id);
