-- Gateway reporting tables for MQTT gateway nodes and periodic heartbeats
-- Requires Supabase/Postgres environment. Assumes helper is_admin(uid uuid) exists.

-- UUID generation
create extension if not exists pgcrypto;

-- 1) Gateway registry
create table if not exists public.gateway_nodes (
  id uuid primary key default gen_random_uuid(),
  name text,
  mqtt_client_id text unique not null,
  version text,
  region text,
  owner_user_id uuid references auth.users(id),
  tags jsonb,
  created_at timestamptz not null default now(),
  updated_at timestamptz not null default now()
);

create index if not exists idx_gateway_nodes_owner on public.gateway_nodes(owner_user_id);

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

drop trigger if exists trg_gateway_nodes_updated_at on public.gateway_nodes;
create trigger trg_gateway_nodes_updated_at
before update on public.gateway_nodes
for each row execute function public.set_updated_at();

alter table public.gateway_nodes enable row level security;

-- RLS: owners and admins can read; only admins can write via client. Service role bypasses RLS.
do $$
begin
  if not exists (
    select 1 from pg_policies where schemaname='public' and tablename='gateway_nodes' and policyname='gateway_nodes_select') then
    create policy gateway_nodes_select on public.gateway_nodes
      for select using (
        auth.uid() = owner_user_id or coalesce(public.is_admin(auth.uid()), false)
      );
  end if;
  if not exists (
    select 1 from pg_policies where schemaname='public' and tablename='gateway_nodes' and policyname='gateway_nodes_update_owner') then
    create policy gateway_nodes_update_owner on public.gateway_nodes
      for update using (
        auth.uid() = owner_user_id or coalesce(public.is_admin(auth.uid()), false)
      ) with check (
        auth.uid() = owner_user_id or coalesce(public.is_admin(auth.uid()), false)
      );
  end if;
  if not exists (
    select 1 from pg_policies where schemaname='public' and tablename='gateway_nodes' and policyname='gateway_nodes_insert_owner') then
    create policy gateway_nodes_insert_owner on public.gateway_nodes
      for insert with check (
        auth.uid() = owner_user_id or coalesce(public.is_admin(auth.uid()), false)
      );
  end if;
end$$;

-- 2) Heartbeats (periodic runtime metrics). Use service role to insert.
create table if not exists public.gateway_heartbeats (
  id uuid primary key default gen_random_uuid(),
  gateway_id uuid not null references public.gateway_nodes(id) on delete cascade,
  ts timestamptz not null default now(),
  uptime_sec integer,
  mem_rss_mb integer,
  heap_used_mb integer,
  mqtt_connected boolean,
  kafka_connected boolean,
  redis_connected boolean,
  msgs_in integer default 0,
  msgs_out integer default 0,
  msgs_dropped integer default 0,
  errors integer default 0,
  acl_denied integer default 0,
  kafka_produced integer default 0,
  extra jsonb
);

create index if not exists idx_gateway_heartbeats_gid_ts on public.gateway_heartbeats(gateway_id, ts desc);

alter table public.gateway_heartbeats enable row level security;

do $$
begin
  if not exists (
    select 1 from pg_policies where schemaname='public' and tablename='gateway_heartbeats' and policyname='gateway_heartbeats_select') then
    create policy gateway_heartbeats_select on public.gateway_heartbeats
      for select using (
        exists (
          select 1 from public.gateway_nodes g
          where g.id = gateway_id
            and (g.owner_user_id = auth.uid() or coalesce(public.is_admin(auth.uid()), false))
        )
      );
  end if;
end$$;

-- 3) Latest status view per gateway
create or replace view public.gateway_status_latest as
select distinct on (g.id)
  g.id as gateway_id,
  g.name,
  g.mqtt_client_id,
  g.version,
  g.region,
  h.ts as last_ts,
  h.uptime_sec,
  h.mem_rss_mb,
  h.heap_used_mb,
  h.mqtt_connected,
  h.kafka_connected,
  h.redis_connected,
  h.msgs_in,
  h.msgs_out,
  h.msgs_dropped,
  h.errors,
  h.acl_denied,
  h.kafka_produced
from public.gateway_nodes g
left join public.gateway_heartbeats h
  on h.gateway_id = g.id
order by g.id, h.ts desc;

-- 4) Daily rollup (materialized view). Refresh nightly via scheduler.
create materialized view if not exists public.gateway_daily_stats as
select
  date_trunc('day', h.ts)::date as day,
  h.gateway_id,
  sum(h.msgs_in) as msgs_in,
  sum(h.msgs_out) as msgs_out,
  sum(h.msgs_dropped) as msgs_dropped,
  sum(h.errors) as errors,
  sum(h.acl_denied) as acl_denied,
  sum(h.kafka_produced) as kafka_produced,
  avg(h.mem_rss_mb) as avg_mem_rss_mb,
  avg(h.heap_used_mb) as avg_heap_used_mb
from public.gateway_heartbeats h
group by 1, 2
with no data;

create index if not exists idx_gateway_daily_stats on public.gateway_daily_stats(day, gateway_id);

-- Note: schedule periodic
-- select cron.schedule('refresh_gateway_daily_stats', '0 3 * * *', $$
--   refresh materialized view concurrently public.gateway_daily_stats;
-- $$);
