-- ==========================================================================
-- Agencia PSI — Migracao: Ajuste manual SaaS admin (WhatsApp credits)
-- ==========================================================================
-- Criado por: Leonardo Nohama
-- Data: 2026-04-23 · Sao Carlos/SP — Brasil
--
-- Contexto:
--   - add_whatsapp_credits (ja existia) so aceita amount > 0, kind fixo.
--   - deduct_whatsapp_credits (ja existia) e exclusiva de uso (kind='usage').
--   - Faltava fluxo de ajuste manual negativo pelo saas admin com safeguards.
--
-- Regras de negocio:
--   1. Admin pode ajustar +/- ate |amount| = 1000 por operacao (anti dedo-gordo).
--      Pra valores maiores, admin repete a operacao (cada uma fica auditada).
--   2. Ao REMOVER (amount < 0), so pode mexer no "pool cortesia":
--      saldo derivado de topup_manual / adjustment / refund.
--      Creditos originados de 'purchase' (compras Asaas/PIX) sao intocaveis —
--      estorno de compra real tem que ir pelo fluxo financeiro do Asaas.
--   3. Regra de consumo (FIFO cortesia primeiro): usage sempre subtrai do
--      pool cortesia antes do pool compra. Formula:
--        removable = max(0, sum_topup_like - usage_total)
--        protected = balance - removable
--      Exemplo: topup 100 + compra 200, usado 50 -> removable=50, protegido=200.
--   4. Exige is_saas_admin() — protege contra chamada de authenticated comum.
-- ==========================================================================

-- ---------------------------------------------------------------------------
-- Helper: breakdown pra UI mostrar removivel vs protegido
-- ---------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.get_whatsapp_removable_balance(p_tenant_id UUID)
RETURNS TABLE (
    balance INT,
    removable INT,
    protected_amount INT,
    topup_net INT,
    usage_total INT
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
    v_balance INT := 0;
    v_topup_net INT := 0;
    v_usage_total INT := 0;
    v_removable INT := 0;
BEGIN
    IF NOT public.is_saas_admin() THEN
        RAISE EXCEPTION 'permission_denied';
    END IF;

    SELECT COALESCE(b.balance, 0) INTO v_balance
        FROM public.whatsapp_credits_balance b
        WHERE b.tenant_id = p_tenant_id;

    v_balance := COALESCE(v_balance, 0);

    SELECT COALESCE(SUM(amount), 0) INTO v_topup_net
        FROM public.whatsapp_credits_transactions
        WHERE tenant_id = p_tenant_id
          AND kind IN ('topup_manual', 'adjustment', 'refund');

    SELECT COALESCE(ABS(SUM(amount)), 0) INTO v_usage_total
        FROM public.whatsapp_credits_transactions
        WHERE tenant_id = p_tenant_id
          AND kind = 'usage';

    v_removable := GREATEST(0, v_topup_net - v_usage_total);
    v_removable := LEAST(v_removable, v_balance);

    RETURN QUERY SELECT
        v_balance,
        v_removable,
        GREATEST(0, v_balance - v_removable),
        v_topup_net,
        v_usage_total;
END;
$$;

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

COMMENT ON FUNCTION public.get_whatsapp_removable_balance(UUID) IS
    'Breakdown do saldo WhatsApp: removivel (pool cortesia restante) vs protegido (compras). Apenas saas_admin.';


-- ---------------------------------------------------------------------------
-- admin_adjust_whatsapp_credits: ajuste manual SaaS admin (+/-)
-- ---------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION public.admin_adjust_whatsapp_credits(
    p_tenant_id UUID,
    p_amount INT,           -- com sinal: positivo=adicionar, negativo=remover
    p_admin_id UUID,
    p_note TEXT DEFAULT NULL
)
RETURNS INT
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
    v_new_balance INT;
    v_current_balance INT;
    v_topup_net INT;
    v_usage_total INT;
    v_removable INT;
    v_clean_note TEXT;
BEGIN
    IF NOT public.is_saas_admin() THEN
        RAISE EXCEPTION 'permission_denied';
    END IF;

    IF p_tenant_id IS NULL THEN
        RAISE EXCEPTION 'tenant_required';
    END IF;

    IF p_amount IS NULL OR p_amount = 0 THEN
        RAISE EXCEPTION 'amount_required';
    END IF;

    IF ABS(p_amount) > 1000 THEN
        RAISE EXCEPTION 'amount_exceeds_limit_1000';
    END IF;

    IF p_admin_id IS NULL THEN
        RAISE EXCEPTION 'admin_id_required';
    END IF;

    v_clean_note := NULLIF(TRIM(COALESCE(p_note, '')), '');
    IF v_clean_note IS NOT NULL THEN
        v_clean_note := LEFT(v_clean_note, 500);
    END IF;

    IF p_amount > 0 THEN
        -- ADICIONAR
        INSERT INTO public.whatsapp_credits_balance (tenant_id, balance)
        VALUES (p_tenant_id, p_amount)
        ON CONFLICT (tenant_id) DO UPDATE SET
            balance = whatsapp_credits_balance.balance + EXCLUDED.balance,
            low_balance_alerted_at = NULL
        RETURNING balance INTO v_new_balance;

    ELSE
        -- REMOVER (amount < 0)
        SELECT balance INTO v_current_balance
            FROM public.whatsapp_credits_balance
            WHERE tenant_id = p_tenant_id
            FOR UPDATE;

        IF NOT FOUND THEN
            RAISE EXCEPTION 'tenant_has_no_balance';
        END IF;

        SELECT COALESCE(SUM(amount), 0) INTO v_topup_net
            FROM public.whatsapp_credits_transactions
            WHERE tenant_id = p_tenant_id
              AND kind IN ('topup_manual', 'adjustment', 'refund');

        SELECT COALESCE(ABS(SUM(amount)), 0) INTO v_usage_total
            FROM public.whatsapp_credits_transactions
            WHERE tenant_id = p_tenant_id
              AND kind = 'usage';

        v_removable := GREATEST(0, v_topup_net - v_usage_total);
        v_removable := LEAST(v_removable, v_current_balance);

        IF ABS(p_amount) > v_removable THEN
            RAISE EXCEPTION 'cannot_remove_beyond_removable: max=%', v_removable;
        END IF;

        UPDATE public.whatsapp_credits_balance
            SET balance = balance + p_amount    -- p_amount ja e negativo
            WHERE tenant_id = p_tenant_id
            RETURNING balance INTO v_new_balance;
    END IF;

    INSERT INTO public.whatsapp_credits_transactions
        (tenant_id, kind, amount, balance_after, admin_id, note)
    VALUES
        (p_tenant_id, 'adjustment', p_amount, v_new_balance, p_admin_id, v_clean_note);

    RETURN v_new_balance;
END;
$$;

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

COMMENT ON FUNCTION public.admin_adjust_whatsapp_credits(UUID, INT, UUID, TEXT) IS
    'Ajuste manual SaaS admin (+/-). |amount|<=1000 por operacao. Remocao so afeta pool cortesia — purchases sao protegidas. Requer is_saas_admin().';
