-- Allow n8n to insert order_groups with the anon key, but only with a private
-- integration secret passed in the x-n8n-secret HTTP header.
--
-- n8n REST headers:
--   apikey: <SUPABASE_ANON_KEY>
--   Authorization: Bearer <SUPABASE_ANON_KEY>
--   x-n8n-secret: <LONG_RANDOM_SECRET>
--   Content-Type: application/json
--   Prefer: resolution=merge-duplicates,return=representation
--
-- Endpoint:
--   POST https://supa.supersamsev.ru/rest/v1/order_groups
--
-- Important:
-- - Keep this secret only in n8n credentials/environment.
-- - Do not put it in the frontend.
-- - Replace CHANGE_ME_LONG_RANDOM_SECRET before running this SQL.

create extension if not exists pgcrypto;

create table if not exists public.integration_api_secrets (
  name text primary key,
  secret_hash text not null,
  created_at timestamptz not null default now()
);

alter table public.integration_api_secrets enable row level security;

drop policy if exists "integration api secrets admin only" on public.integration_api_secrets;
create policy "integration api secrets admin only"
on public.integration_api_secrets
for all
using (public.current_role_name() = 'admin')
with check (public.current_role_name() = 'admin');

insert into public.integration_api_secrets (name, secret_hash)
values (
  'n8n_order_groups_insert',
  crypt('CHANGE_ME_LONG_RANDOM_SECRET', gen_salt('bf'))
)
on conflict (name) do update
set secret_hash = excluded.secret_hash;

create or replace function public.is_valid_n8n_order_groups_secret()
returns boolean
language sql
stable
security definer
set search_path = public
as $$
  select coalesce(
    exists (
      select 1
      from public.integration_api_secrets s
      where s.name = 'n8n_order_groups_insert'
        and crypt(
          nullif(current_setting('request.headers', true)::jsonb ->> 'x-n8n-secret', ''),
          s.secret_hash
        ) = s.secret_hash
    ),
    false
  );
$$;

revoke all on function public.is_valid_n8n_order_groups_secret() from public;
grant execute on function public.is_valid_n8n_order_groups_secret() to anon, authenticated;

alter table public.order_groups enable row level security;

drop policy if exists "order groups insert service roles" on public.order_groups;
drop policy if exists "order groups insert coordination and integration roles" on public.order_groups;
drop policy if exists "order groups insert n8n anon secret" on public.order_groups;

create policy "order groups insert n8n anon secret"
on public.order_groups
for insert
to anon
with check (public.is_valid_n8n_order_groups_secret());

create policy "order groups insert coordination and integration roles"
on public.order_groups
for insert
to authenticated
with check (
  public.current_role_name() in ('manager', 'logistician', 'admin', 'integration')
);

-- If n8n uses upsert, update must also be allowed for the same anon secret.
drop policy if exists "order groups update n8n anon secret" on public.order_groups;
drop policy if exists "order groups update coordination roles" on public.order_groups;
drop policy if exists "order groups update coordination and integration roles" on public.order_groups;

create policy "order groups update n8n anon secret"
on public.order_groups
for update
to anon
using (public.is_valid_n8n_order_groups_secret())
with check (public.is_valid_n8n_order_groups_secret());

create policy "order groups update coordination and integration roles"
on public.order_groups
for update
to authenticated
using (
  public.current_role_name() in ('manager', 'logistician', 'admin', 'integration')
)
with check (
  public.current_role_name() in ('manager', 'logistician', 'admin', 'integration')
);

-- Diagnostics:
-- select policyname, cmd, roles, qual, with_check
-- from pg_policies
-- where schemaname = 'public' and tablename = 'order_groups'
-- order by policyname;
