-- =============================================================================
-- Freemium F3a — Blacklist de e-mails e slugs
--
-- ⚠️ APLICAR COMO supabase_admin (cria trigger em auth.users + altera
--    slug_disponivel, que é owned por supabase_admin).
--
-- Tabela blacklist (kind email|slug). E-mail bloqueia o cadastro DE VERDADE via
-- trigger BEFORE INSERT em auth.users (não só no front); suporta domínio inteiro
-- com entrada '@dominio.com'. Slug integra no slug_disponivel (motivo 'bloqueado').
-- Gerida por saas_admin (dev) em Configurações.
-- =============================================================================

BEGIN;

CREATE TABLE IF NOT EXISTS public.blacklist (
    id         uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    kind       text NOT NULL CHECK (kind IN ('email','slug')),
    value      text NOT NULL,
    note       text,
    created_by uuid,
    created_at timestamptz NOT NULL DEFAULT now(),
    UNIQUE (kind, value)
);

-- normaliza value (lower+trim) sempre
CREATE OR REPLACE FUNCTION public.blacklist_normalize()
RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
    NEW.value := lower(trim(NEW.value));
    IF NEW.value = '' THEN RAISE EXCEPTION 'valor vazio'; END IF;
    RETURN NEW;
END $$;
DROP TRIGGER IF EXISTS trg_blacklist_normalize ON public.blacklist;
CREATE TRIGGER trg_blacklist_normalize BEFORE INSERT OR UPDATE ON public.blacklist
    FOR EACH ROW EXECUTE FUNCTION public.blacklist_normalize();

-- RLS: só saas_admin gere
ALTER TABLE public.blacklist ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS blacklist_saas_admin ON public.blacklist;
CREATE POLICY blacklist_saas_admin ON public.blacklist
    FOR ALL USING (public.is_saas_admin()) WITH CHECK (public.is_saas_admin());

-- helpers ----------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.is_email_blacklisted(p_email text)
RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
    SELECT EXISTS (
        SELECT 1 FROM public.blacklist
        WHERE kind = 'email'
          AND value IN (
              lower(trim(p_email)),
              '@' || split_part(lower(trim(p_email)), '@', 2)
          )
    );
$$;
ALTER FUNCTION public.is_email_blacklisted(text) OWNER TO supabase_admin;

CREATE OR REPLACE FUNCTION public.is_slug_blacklisted(p_slug text)
RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
    SELECT EXISTS (SELECT 1 FROM public.blacklist WHERE kind = 'slug' AND value = lower(trim(p_slug)));
$$;
ALTER FUNCTION public.is_slug_blacklisted(text) OWNER TO supabase_admin;

-- trigger de bloqueio real no cadastro -----------------------------------------
CREATE OR REPLACE FUNCTION public.enforce_email_blacklist()
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
BEGIN
    IF NEW.email IS NOT NULL AND public.is_email_blacklisted(NEW.email) THEN
        RAISE EXCEPTION 'EMAIL_BLOCKED' USING ERRCODE = 'P0001';
    END IF;
    RETURN NEW;
END $$;
ALTER FUNCTION public.enforce_email_blacklist() OWNER TO supabase_admin;

DROP TRIGGER IF EXISTS trg_enforce_email_blacklist ON auth.users;
CREATE TRIGGER trg_enforce_email_blacklist BEFORE INSERT ON auth.users
    FOR EACH ROW EXECUTE FUNCTION public.enforce_email_blacklist();

-- integra no slug_disponivel (motivo 'bloqueado') ------------------------------
CREATE OR REPLACE FUNCTION public.slug_disponivel(p_slug text)
RETURNS jsonb
LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path TO 'public','pg_temp'
AS $$
DECLARE
    v text := lower(trim(coalesce(p_slug, '')));
    v_reservados text[] := ARRAY['public','tenant','admin','www','api','app','auth','supabase','postgres','saas','suporte','support'];
BEGIN
    IF length(v) < 3 THEN RETURN jsonb_build_object('ok', false, 'motivo', 'curto'); END IF;
    IF length(v) > 48 THEN RETURN jsonb_build_object('ok', false, 'motivo', 'longo'); END IF;
    IF v !~ '^[a-z][a-z0-9_]*$' THEN RETURN jsonb_build_object('ok', false, 'motivo', 'invalido'); END IF;
    IF v = ANY(v_reservados) THEN RETURN jsonb_build_object('ok', false, 'motivo', 'reservado'); END IF;
    IF public.is_slug_blacklisted(v) THEN RETURN jsonb_build_object('ok', false, 'motivo', 'bloqueado'); END IF;
    IF EXISTS (SELECT 1 FROM public.tenants WHERE slug = v) THEN RETURN jsonb_build_object('ok', false, 'motivo', 'em_uso'); END IF;
    RETURN jsonb_build_object('ok', true, 'motivo', 'disponivel');
END $$;
ALTER FUNCTION public.slug_disponivel(text) OWNER TO supabase_admin;
REVOKE ALL ON FUNCTION public.slug_disponivel(text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.slug_disponivel(text) TO anon, authenticated, service_role;

GRANT SELECT, INSERT, UPDATE, DELETE ON public.blacklist TO authenticated;

COMMIT;
