-- v1 initial schema for linumiq tunnel platform
-- Phase 2 / Wave A backend

BEGIN;

CREATE EXTENSION IF NOT EXISTS citext;

-- ---------------------------------------------------------------------------
-- Tables
-- ---------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS public.tunnels (
  user_id      uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  subdomain    citext UNIQUE NOT NULL
                 CHECK (subdomain ~ '^[a-z0-9-]{3,32}$'
                        AND subdomain NOT IN ('app','api','www','admin','auth','mail','static')),
  token        text UNIQUE NOT NULL,
  is_active    boolean NOT NULL DEFAULT true,
  bytes_used   bigint NOT NULL DEFAULT 0,
  quota_bytes  bigint NOT NULL DEFAULT 1099511627776,
  created_at   timestamptz NOT NULL DEFAULT now(),
  last_seen_at timestamptz
);

CREATE TABLE IF NOT EXISTS public.subscriptions (
  user_id    uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  plan       text NOT NULL DEFAULT 'free',
  status     text NOT NULL DEFAULT 'active',
  updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS public.usage_samples (
  id          bigserial PRIMARY KEY,
  subdomain   citext NOT NULL,
  ts          timestamptz NOT NULL DEFAULT now(),
  bytes_delta bigint NOT NULL
);
CREATE INDEX IF NOT EXISTS usage_samples_subdomain_ts_idx
  ON public.usage_samples (subdomain, ts DESC);

CREATE TABLE IF NOT EXISTS public.users_profile (
  user_id    uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  email      text,
  created_at timestamptz NOT NULL DEFAULT now()
);

-- ---------------------------------------------------------------------------
-- Trigger: auto-create users_profile row on auth.users insert
-- ---------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
  INSERT INTO public.users_profile (user_id, email)
  VALUES (NEW.id, NEW.email)
  ON CONFLICT (user_id) DO NOTHING;
  RETURN NEW;
END;
$$;

REVOKE ALL ON FUNCTION public.handle_new_user() FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.handle_new_user() TO supabase_auth_admin;

DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
CREATE TRIGGER on_auth_user_created
  AFTER INSERT ON auth.users
  FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();

-- ---------------------------------------------------------------------------
-- Row-level security
-- ---------------------------------------------------------------------------

ALTER TABLE public.tunnels       ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.subscriptions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.usage_samples ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.users_profile ENABLE ROW LEVEL SECURITY;

-- tunnels: owner can SELECT and UPDATE. No INSERT/DELETE for users.
DROP POLICY IF EXISTS tunnels_select_own ON public.tunnels;
CREATE POLICY tunnels_select_own ON public.tunnels
  FOR SELECT TO authenticated
  USING (auth.uid() = user_id);

DROP POLICY IF EXISTS tunnels_update_own ON public.tunnels;
CREATE POLICY tunnels_update_own ON public.tunnels
  FOR UPDATE TO authenticated
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

-- subscriptions: owner can SELECT.
DROP POLICY IF EXISTS subscriptions_select_own ON public.subscriptions;
CREATE POLICY subscriptions_select_own ON public.subscriptions
  FOR SELECT TO authenticated
  USING (auth.uid() = user_id);

-- usage_samples: no anon/authenticated access (service_role bypasses RLS).
-- (No policies created → all access denied for non-service roles.)

-- users_profile: owner can SELECT and UPDATE.
DROP POLICY IF EXISTS users_profile_select_own ON public.users_profile;
CREATE POLICY users_profile_select_own ON public.users_profile
  FOR SELECT TO authenticated
  USING (auth.uid() = user_id);

DROP POLICY IF EXISTS users_profile_update_own ON public.users_profile;
CREATE POLICY users_profile_update_own ON public.users_profile
  FOR UPDATE TO authenticated
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

-- ---------------------------------------------------------------------------
-- Grants: let PostgREST roles see the tables; RLS still gates access.
-- ---------------------------------------------------------------------------

GRANT USAGE ON SCHEMA public TO anon, authenticated, service_role;

GRANT SELECT, UPDATE ON public.tunnels       TO authenticated;
GRANT SELECT         ON public.subscriptions TO authenticated;
GRANT SELECT, UPDATE ON public.users_profile TO authenticated;

GRANT ALL ON public.tunnels, public.subscriptions, public.usage_samples, public.users_profile TO service_role;
GRANT USAGE, SELECT ON SEQUENCE public.usage_samples_id_seq TO service_role;

COMMIT;
