-- =============================================================================
-- Migration: 20260419000008_saas_twilio_config
-- Permite saas_admin editar config Twilio operacional pelo painel, sem redeploy.
--
-- DECISÃO DE SEGURANÇA:
--   • TWILIO_AUTH_TOKEN (secret) NÃO entra na tabela. Continua em env var
--     da Edge Function. Painel apenas exibe se está configurado (best-effort).
--   • TWILIO_ACCOUNT_SID (público no Twilio dashboard, identificador) → DB
--   • TWILIO_WHATSAPP_WEBHOOK (URL) → DB
--   • USD_BRL_RATE / MARGIN_MULTIPLIER (operacional) → DB
--
-- Edge function: lê primeiro do banco; cai pra env vars como fallback se row
-- ainda não foi configurada (back-compat com deploys antigos).
-- =============================================================================

CREATE TABLE IF NOT EXISTS public.saas_twilio_config (
    id                          boolean PRIMARY KEY DEFAULT true,
    account_sid                 text,
    whatsapp_webhook_url        text,
    usd_brl_rate                numeric(10,4) NOT NULL DEFAULT 5.5,
    margin_multiplier           numeric(10,4) NOT NULL DEFAULT 1.4,
    notes                       text,
    updated_at                  timestamptz NOT NULL DEFAULT now(),
    updated_by                  uuid,
    CONSTRAINT saas_twilio_config_singleton CHECK (id = true),
    CONSTRAINT saas_twilio_config_rate_chk  CHECK (usd_brl_rate > 0 AND usd_brl_rate < 100),
    CONSTRAINT saas_twilio_config_mult_chk  CHECK (margin_multiplier >= 1 AND margin_multiplier <= 10),
    CONSTRAINT saas_twilio_config_sid_chk   CHECK (account_sid IS NULL OR account_sid ~ '^AC[a-zA-Z0-9]{32}$'),
    CONSTRAINT saas_twilio_config_url_chk   CHECK (whatsapp_webhook_url IS NULL OR whatsapp_webhook_url ~ '^https?://')
);

INSERT INTO public.saas_twilio_config (id) VALUES (true)
ON CONFLICT (id) DO NOTHING;

ALTER TABLE public.saas_twilio_config ENABLE ROW LEVEL SECURITY;

REVOKE ALL ON public.saas_twilio_config FROM anon, authenticated;
GRANT  SELECT ON public.saas_twilio_config TO authenticated;

DROP POLICY IF EXISTS saas_twilio_config_read ON public.saas_twilio_config;
CREATE POLICY saas_twilio_config_read ON public.saas_twilio_config
  FOR SELECT TO authenticated
  USING (public.is_saas_admin());  -- só admin vê config (mesmo sem secret, é dado operacional)

COMMENT ON TABLE public.saas_twilio_config IS
  'Config operacional Twilio editável via painel. AUTH_TOKEN continua em env var por segurança.';

-- ─────────────────────────────────────────────────────────────────────────
-- RPC get_twilio_config — retorna config atual (saas_admin OU service_role)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_twilio_config()
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public'
AS $function$
DECLARE
    cfg saas_twilio_config%ROWTYPE;
BEGIN
    -- Permite quem é saas_admin (UI) ou quando chamado via service_role (edge function)
    -- coalesce protege de NULL (auth.role() pode ser NULL fora de contexto JWT)
    IF NOT (public.is_saas_admin() OR coalesce(auth.role(), '') = 'service_role') THEN
        RAISE EXCEPTION 'Sem permissão' USING ERRCODE = '42501';
    END IF;

    SELECT * INTO cfg FROM saas_twilio_config WHERE id = true;
    IF NOT FOUND THEN
        RETURN jsonb_build_object(
            'account_sid',          NULL,
            'whatsapp_webhook_url', NULL,
            'usd_brl_rate',         5.5,
            'margin_multiplier',    1.4
        );
    END IF;

    RETURN jsonb_build_object(
        'account_sid',          cfg.account_sid,
        'whatsapp_webhook_url', cfg.whatsapp_webhook_url,
        'usd_brl_rate',         cfg.usd_brl_rate,
        'margin_multiplier',    cfg.margin_multiplier,
        'notes',                cfg.notes,
        'updated_at',           cfg.updated_at,
        'updated_by',           cfg.updated_by
    );
END;
$function$;

REVOKE ALL ON FUNCTION public.get_twilio_config() FROM PUBLIC, anon, authenticated;
GRANT  EXECUTE ON FUNCTION public.get_twilio_config() TO authenticated, service_role;

-- ─────────────────────────────────────────────────────────────────────────
-- RPC update_twilio_config — só saas_admin
-- -----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.update_twilio_config(
    p_account_sid          text DEFAULT NULL,
    p_whatsapp_webhook_url text DEFAULT NULL,
    p_usd_brl_rate         numeric DEFAULT NULL,
    p_margin_multiplier    numeric DEFAULT NULL,
    p_notes                text DEFAULT NULL
)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public'
AS $function$
DECLARE
    v_caller         uuid := auth.uid();
    v_account_sid    text;
    v_webhook_url    text;
    v_notes          text;
BEGIN
    IF v_caller IS NULL THEN
        RAISE EXCEPTION 'Não autenticado' USING ERRCODE = '28000';
    END IF;
    IF NOT public.is_saas_admin() THEN
        RAISE EXCEPTION 'Apenas saas_admin pode atualizar config Twilio' USING ERRCODE = '42501';
    END IF;

    -- Sanitização
    v_account_sid := nullif(btrim(coalesce(p_account_sid, '')), '');
    v_webhook_url := nullif(btrim(coalesce(p_whatsapp_webhook_url, '')), '');
    v_notes       := nullif(btrim(coalesce(p_notes, '')), '');

    IF v_account_sid IS NOT NULL AND v_account_sid !~ '^AC[a-zA-Z0-9]{32}$' THEN
        RAISE EXCEPTION 'account_sid inválido (esperado AC + 32 chars)' USING ERRCODE = '22023';
    END IF;
    IF v_webhook_url IS NOT NULL AND v_webhook_url !~ '^https?://' THEN
        RAISE EXCEPTION 'webhook_url deve começar com http(s)://' USING ERRCODE = '22023';
    END IF;
    IF p_usd_brl_rate IS NOT NULL AND (p_usd_brl_rate <= 0 OR p_usd_brl_rate >= 100) THEN
        RAISE EXCEPTION 'usd_brl_rate fora da faixa (0..100)' USING ERRCODE = '22023';
    END IF;
    IF p_margin_multiplier IS NOT NULL AND (p_margin_multiplier < 1 OR p_margin_multiplier > 10) THEN
        RAISE EXCEPTION 'margin_multiplier fora da faixa (1..10)' USING ERRCODE = '22023';
    END IF;
    IF v_notes IS NOT NULL AND length(v_notes) > 1000 THEN
        v_notes := substring(v_notes FROM 1 FOR 1000);
    END IF;

    UPDATE saas_twilio_config
       SET account_sid          = COALESCE(v_account_sid, account_sid),
           whatsapp_webhook_url = COALESCE(v_webhook_url, whatsapp_webhook_url),
           usd_brl_rate         = COALESCE(p_usd_brl_rate, usd_brl_rate),
           margin_multiplier    = COALESCE(p_margin_multiplier, margin_multiplier),
           notes                = COALESCE(v_notes, notes),
           updated_at           = now(),
           updated_by           = v_caller
     WHERE id = true;

    RETURN public.get_twilio_config();
END;
$function$;

REVOKE ALL ON FUNCTION public.update_twilio_config(text, text, numeric, numeric, text) FROM PUBLIC, anon, authenticated;
GRANT  EXECUTE ON FUNCTION public.update_twilio_config(text, text, numeric, numeric, text) TO authenticated;
