-- ==========================================================================
-- Agencia PSI — Migracao: Sistema de créditos WhatsApp (Marco B)
-- ==========================================================================
-- Criado por: Leonardo Nohama
-- Data: 2026-04-21 · Sao Carlos/SP — Brasil
--
-- Modelo:
--   - whatsapp_credits_balance     → saldo atual por tenant (snapshot)
--   - whatsapp_credits_transactions → extrato (purchase, usage, topup, adj)
--   - whatsapp_credit_packages     → pacotes oferecidos (SaaS-managed)
--   - whatsapp_credit_purchases    → ordens de compra via Asaas
--
-- Helpers (RPC):
--   - add_whatsapp_credits(tenant, amount, kind, ...) → novo saldo
--   - deduct_whatsapp_credits(tenant, amount, message_id) → boolean
--
-- Creditos so sao deduzidos quando o tenant usa provider='twilio'
-- (Evolution e free).
-- ==========================================================================

-- ---------------------------------------------------------------------------
-- Saldo por tenant
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.whatsapp_credits_balance (
    tenant_id UUID PRIMARY KEY REFERENCES public.tenants(id) ON DELETE CASCADE,
    balance INT NOT NULL DEFAULT 0 CHECK (balance >= 0),
    lifetime_purchased INT NOT NULL DEFAULT 0,
    lifetime_used INT NOT NULL DEFAULT 0,
    low_balance_threshold INT NOT NULL DEFAULT 20 CHECK (low_balance_threshold >= 0),
    low_balance_alerted_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

DROP TRIGGER IF EXISTS trg_wa_credits_balance_updated_at ON public.whatsapp_credits_balance;
CREATE TRIGGER trg_wa_credits_balance_updated_at
    BEFORE UPDATE ON public.whatsapp_credits_balance
    FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();

COMMENT ON TABLE public.whatsapp_credits_balance IS
    'Saldo atual de creditos WhatsApp por tenant. 1 credito = 1 mensagem Twilio.';

-- ---------------------------------------------------------------------------
-- Extrato (transações)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.whatsapp_credits_transactions (
    id BIGSERIAL PRIMARY KEY,
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
    kind TEXT NOT NULL CHECK (kind IN ('purchase', 'usage', 'topup_manual', 'refund', 'adjustment')),
    amount INT NOT NULL,        -- positivo = credito, negativo = debito
    balance_after INT NOT NULL,

    -- Referencias opcionais
    conversation_message_id BIGINT REFERENCES public.conversation_messages(id) ON DELETE SET NULL,
    purchase_id UUID,
    admin_id UUID REFERENCES auth.users(id) ON DELETE SET NULL,
    note TEXT,

    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_wa_credits_tx_tenant_created
    ON public.whatsapp_credits_transactions (tenant_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_wa_credits_tx_kind
    ON public.whatsapp_credits_transactions (tenant_id, kind, created_at DESC);

COMMENT ON TABLE public.whatsapp_credits_transactions IS
    'Extrato de creditos WhatsApp. Append-only — nao editar/deletar.';

-- ---------------------------------------------------------------------------
-- Pacotes (global, gerenciado pelo SaaS admin)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.whatsapp_credit_packages (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name TEXT NOT NULL CHECK (length(name) > 0 AND length(name) <= 100),
    description TEXT,
    credits INT NOT NULL CHECK (credits > 0),
    price_brl NUMERIC(10,2) NOT NULL CHECK (price_brl > 0),
    is_active BOOLEAN NOT NULL DEFAULT true,
    is_featured BOOLEAN NOT NULL DEFAULT false,
    position INT NOT NULL DEFAULT 100,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

DROP TRIGGER IF EXISTS trg_wa_credit_packages_updated_at ON public.whatsapp_credit_packages;
CREATE TRIGGER trg_wa_credit_packages_updated_at
    BEFORE UPDATE ON public.whatsapp_credit_packages
    FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();

CREATE INDEX IF NOT EXISTS idx_wa_credit_packages_active
    ON public.whatsapp_credit_packages (is_active, position, price_brl)
    WHERE is_active = true;

COMMENT ON TABLE public.whatsapp_credit_packages IS
    'Pacotes de creditos disponiveis pra compra. Gerenciado pelo SaaS admin.';

-- Seed: pacotes padrao
INSERT INTO public.whatsapp_credit_packages (name, description, credits, price_brl, is_featured, position) VALUES
    ('Iniciante', 'Ideal pra conhecer a plataforma', 100, 49.90, false, 10),
    ('Profissional', 'Mais vendido pra clínicas pequenas', 500, 199.90, true, 20),
    ('Clínica', 'Pra clínicas com alto volume', 1500, 499.90, false, 30),
    ('Enterprise', 'Pacote grande com desconto', 5000, 1499.90, false, 40)
ON CONFLICT DO NOTHING;

-- ---------------------------------------------------------------------------
-- Ordens de compra (Asaas integration)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS public.whatsapp_credit_purchases (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
    package_id UUID REFERENCES public.whatsapp_credit_packages(id) ON DELETE SET NULL,

    -- Snapshot do pacote no momento da compra (caso mude de preço/creditos depois)
    package_name TEXT NOT NULL,
    credits INT NOT NULL CHECK (credits > 0),
    amount_brl NUMERIC(10,2) NOT NULL CHECK (amount_brl > 0),

    status TEXT NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'paid', 'failed', 'expired', 'refunded', 'cancelled')),

    -- Asaas integration
    asaas_customer_id TEXT,
    asaas_payment_id TEXT,
    asaas_payment_link TEXT,
    asaas_pix_qrcode TEXT,          -- base64 da imagem
    asaas_pix_copy_paste TEXT,      -- codigo PIX copia-cola

    paid_at TIMESTAMPTZ,
    expires_at TIMESTAMPTZ,
    failed_at TIMESTAMPTZ,

    created_by UUID REFERENCES auth.users(id) ON DELETE SET NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

DROP TRIGGER IF EXISTS trg_wa_credit_purchases_updated_at ON public.whatsapp_credit_purchases;
CREATE TRIGGER trg_wa_credit_purchases_updated_at
    BEFORE UPDATE ON public.whatsapp_credit_purchases
    FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();

CREATE INDEX IF NOT EXISTS idx_wa_credit_purchases_tenant
    ON public.whatsapp_credit_purchases (tenant_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_wa_credit_purchases_status
    ON public.whatsapp_credit_purchases (status, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_wa_credit_purchases_asaas_payment
    ON public.whatsapp_credit_purchases (asaas_payment_id)
    WHERE asaas_payment_id IS NOT NULL;

-- FK pra transactions.purchase_id (circular, então define depois)
ALTER TABLE public.whatsapp_credits_transactions
    DROP CONSTRAINT IF EXISTS whatsapp_credits_transactions_purchase_id_fkey;
ALTER TABLE public.whatsapp_credits_transactions
    ADD CONSTRAINT whatsapp_credits_transactions_purchase_id_fkey
    FOREIGN KEY (purchase_id) REFERENCES public.whatsapp_credit_purchases(id) ON DELETE SET NULL;

COMMENT ON TABLE public.whatsapp_credit_purchases IS
    'Ordens de compra de creditos via Asaas. Webhook atualiza status.';

-- ---------------------------------------------------------------------------
-- RPC: add_whatsapp_credits (SECURITY DEFINER — atualiza saldo + registra tx)
-- ---------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.add_whatsapp_credits(
    p_tenant_id UUID,
    p_amount INT,
    p_kind TEXT,
    p_purchase_id UUID DEFAULT NULL,
    p_admin_id UUID DEFAULT NULL,
    p_note TEXT DEFAULT NULL
)
RETURNS INT
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
    v_new_balance INT;
BEGIN
    IF p_amount <= 0 THEN
        RAISE EXCEPTION 'amount must be positive';
    END IF;
    IF p_kind NOT IN ('purchase', 'topup_manual', 'refund', 'adjustment') THEN
        RAISE EXCEPTION 'invalid kind for credit: %', p_kind;
    END IF;

    INSERT INTO public.whatsapp_credits_balance (tenant_id, balance, lifetime_purchased)
    VALUES (p_tenant_id, p_amount, CASE WHEN p_kind IN ('purchase', 'topup_manual') THEN p_amount ELSE 0 END)
    ON CONFLICT (tenant_id) DO UPDATE SET
        balance = whatsapp_credits_balance.balance + EXCLUDED.balance,
        lifetime_purchased = whatsapp_credits_balance.lifetime_purchased
            + CASE WHEN p_kind IN ('purchase', 'topup_manual') THEN p_amount ELSE 0 END,
        low_balance_alerted_at = NULL  -- reset alerta quando recebe creditos
    RETURNING balance INTO v_new_balance;

    INSERT INTO public.whatsapp_credits_transactions
        (tenant_id, kind, amount, balance_after, purchase_id, admin_id, note)
    VALUES
        (p_tenant_id, p_kind, p_amount, v_new_balance, p_purchase_id, p_admin_id, p_note);

    RETURN v_new_balance;
END;
$$;

REVOKE ALL ON FUNCTION public.add_whatsapp_credits(UUID, INT, TEXT, UUID, UUID, TEXT) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.add_whatsapp_credits(UUID, INT, TEXT, UUID, UUID, TEXT) TO service_role;

-- ---------------------------------------------------------------------------
-- RPC: deduct_whatsapp_credits (atomico, falha se saldo insuficiente)
-- ---------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.deduct_whatsapp_credits(
    p_tenant_id UUID,
    p_amount INT,
    p_conversation_message_id BIGINT DEFAULT NULL,
    p_note TEXT DEFAULT NULL
)
RETURNS INT
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
    v_new_balance INT;
    v_row RECORD;
BEGIN
    IF p_amount <= 0 THEN
        RAISE EXCEPTION 'amount must be positive';
    END IF;

    -- Lock a linha e valida saldo
    SELECT balance, low_balance_threshold
        INTO v_row
        FROM public.whatsapp_credits_balance
        WHERE tenant_id = p_tenant_id
        FOR UPDATE;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'insufficient_credits';
    END IF;
    IF v_row.balance < p_amount THEN
        RAISE EXCEPTION 'insufficient_credits';
    END IF;

    UPDATE public.whatsapp_credits_balance
        SET balance = balance - p_amount,
            lifetime_used = lifetime_used + p_amount
        WHERE tenant_id = p_tenant_id
        RETURNING balance INTO v_new_balance;

    INSERT INTO public.whatsapp_credits_transactions
        (tenant_id, kind, amount, balance_after, conversation_message_id, note)
    VALUES
        (p_tenant_id, 'usage', -p_amount, v_new_balance, p_conversation_message_id, p_note);

    RETURN v_new_balance;
END;
$$;

REVOKE ALL ON FUNCTION public.deduct_whatsapp_credits(UUID, INT, BIGINT, TEXT) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.deduct_whatsapp_credits(UUID, INT, BIGINT, TEXT) TO service_role;

-- ---------------------------------------------------------------------------
-- RLS
-- ---------------------------------------------------------------------------
ALTER TABLE public.whatsapp_credits_balance ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.whatsapp_credits_transactions ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.whatsapp_credit_packages ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.whatsapp_credit_purchases ENABLE ROW LEVEL SECURITY;

-- Balance: members do tenant leem, saas_admin tudo
DROP POLICY IF EXISTS "wa_credits_balance: select tenant" ON public.whatsapp_credits_balance;
CREATE POLICY "wa_credits_balance: select tenant"
    ON public.whatsapp_credits_balance FOR SELECT TO authenticated
    USING (
        public.is_saas_admin()
        OR EXISTS (
            SELECT 1 FROM public.tenant_members tm
            WHERE tm.user_id = auth.uid() AND tm.tenant_id = whatsapp_credits_balance.tenant_id AND tm.status = 'active'
        )
    );

-- Settings update: members do tenant podem alterar low_balance_threshold
DROP POLICY IF EXISTS "wa_credits_balance: update tenant" ON public.whatsapp_credits_balance;
CREATE POLICY "wa_credits_balance: update tenant"
    ON public.whatsapp_credits_balance FOR UPDATE TO authenticated
    USING (
        public.is_saas_admin()
        OR EXISTS (
            SELECT 1 FROM public.tenant_members tm
            WHERE tm.user_id = auth.uid() AND tm.tenant_id = whatsapp_credits_balance.tenant_id AND tm.status = 'active'
        )
    )
    WITH CHECK (
        public.is_saas_admin()
        OR EXISTS (
            SELECT 1 FROM public.tenant_members tm
            WHERE tm.user_id = auth.uid() AND tm.tenant_id = whatsapp_credits_balance.tenant_id AND tm.status = 'active'
        )
    );

-- Transactions: read-only pra tenant members, write via RPC
DROP POLICY IF EXISTS "wa_credits_tx: select tenant" ON public.whatsapp_credits_transactions;
CREATE POLICY "wa_credits_tx: select tenant"
    ON public.whatsapp_credits_transactions FOR SELECT TO authenticated
    USING (
        public.is_saas_admin()
        OR EXISTS (
            SELECT 1 FROM public.tenant_members tm
            WHERE tm.user_id = auth.uid() AND tm.tenant_id = whatsapp_credits_transactions.tenant_id AND tm.status = 'active'
        )
    );

-- Packages: todos leem os ativos; saas_admin gerencia
DROP POLICY IF EXISTS "wa_packages: select active" ON public.whatsapp_credit_packages;
CREATE POLICY "wa_packages: select active"
    ON public.whatsapp_credit_packages FOR SELECT TO authenticated
    USING (is_active = true OR public.is_saas_admin());

DROP POLICY IF EXISTS "wa_packages: manage saas admin" ON public.whatsapp_credit_packages;
CREATE POLICY "wa_packages: manage saas admin"
    ON public.whatsapp_credit_packages FOR ALL TO authenticated
    USING (public.is_saas_admin())
    WITH CHECK (public.is_saas_admin());

-- Purchases: members do tenant leem as proprias
DROP POLICY IF EXISTS "wa_purchases: select tenant" ON public.whatsapp_credit_purchases;
CREATE POLICY "wa_purchases: select tenant"
    ON public.whatsapp_credit_purchases FOR SELECT TO authenticated
    USING (
        public.is_saas_admin()
        OR EXISTS (
            SELECT 1 FROM public.tenant_members tm
            WHERE tm.user_id = auth.uid() AND tm.tenant_id = whatsapp_credit_purchases.tenant_id AND tm.status = 'active'
        )
    );

-- ==========================================================================
-- FIM DA MIGRACAO
-- ==========================================================================
