<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/views/pages/saas/SaasDashboard.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import { supabase } from '@/lib/supabase/client';
import { logError } from '@/support/supportLogger';
import { useRouter } from 'vue-router';
import { useToast } from 'primevue/usetoast';
import { useConfirm } from 'primevue/useconfirm';

import Chart from 'primevue/chart';
import SaasCreditsRevenueCard from '@/components/dashboard/SaasCreditsRevenueCard.vue';

const router = useRouter();
const toast = useToast();
const confirm = useConfirm();

const loading = ref(false);

// KPIs
const totalActive = ref(0);
const totalCanceled = ref(0);
const totalMismatches = ref(0);

const plans = ref([]); // plans: id,key,target,is_active
const prices = ref([]); // v_plan_active_prices
const subs = ref([]); // subscriptions

// ------------------------------------
// Intenções de assinatura (subscription_intents)
// ------------------------------------
const intents = ref([]);
const intentsLoading = ref(false);
const intentsLimit = ref(12); // quantas mostrar no card
const totalIntents = ref(0);
const totalIntentsNew = ref(0);
const totalIntentsPaid = ref(0);

// intervalo de exibição (MRR / ARPA)
const intervalView = ref('month'); // 'month' | 'year'
const intervalOptions = [
    { label: 'Mensal (MRR)', value: 'month' },
    { label: 'Anual (ARR)', value: 'year' }
];

const lastUpdatedAt = ref(null);

// ------------------------------------
// Utils
// ------------------------------------
function moneyBRLFromCents(cents) {
    const v = Number(cents || 0) / 100;
    return v.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
}

function planTargetLabel(t) {
    if (t === 'clinic') return 'Clínica';
    if (t === 'therapist') return 'Terapeuta';
    return '—';
}

function planTargetSeverity(t) {
    if (t === 'clinic') return 'info';
    if (t === 'therapist') return 'success';
    return 'secondary';
}

function fmtDate(iso) {
    if (!iso) return '—';
    const d = new Date(iso);
    if (Number.isNaN(d.getTime())) return String(iso);
    return d.toLocaleString('pt-BR');
}

function intervalLabel(v) {
    if (v === 'month') return 'Mensal';
    if (v === 'year') return 'Anual';
    return v || '—';
}

function statusSeverity(s) {
    const st = String(s || '').toLowerCase();
    if (st === 'new') return 'info';
    if (st === 'paid') return 'success';
    if (st === 'canceled') return 'danger';
    if (st === 'expired') return 'warning';
    return 'secondary';
}

function maskEmail(email) {
    const e = String(email || '').trim();
    if (!e.includes('@')) return e || '—';
    const [u, d] = e.split('@');
    if (!u) return `***@${d}`;
    const head = u.slice(0, 1);
    return `${head}***@${d}`;
}

// ------------------------------------
// Preços (view)
// ------------------------------------
const priceByPlanId = computed(() => {
    const m = new Map();
    for (const r of prices.value || []) m.set(r.plan_id, r);
    return m;
});

function priceCentsForPlan(planId, interval) {
    const pr = priceByPlanId.value.get(planId);
    if (!pr) return null;
    return interval === 'year' ? (pr.yearly_cents ?? null) : (pr.monthly_cents ?? null);
}

function normalizedRevenueCents(planId, viewInterval) {
    const m = priceCentsForPlan(planId, 'month');
    const y = priceCentsForPlan(planId, 'year');

    if (viewInterval === 'month') {
        if (m != null) return Number(m);
        if (y != null) return Math.round(Number(y) / 12);
        return 0;
    }

    if (y != null) return Number(y);
    if (m != null) return Math.round(Number(m) * 12);
    return 0;
}

// ------------------------------------
// KPIs
// ------------------------------------
const activeSubs = computed(() => (subs.value || []).filter((s) => String(s.status) === 'active'));

const revenueCents = computed(() => {
    let sum = 0;
    for (const s of activeSubs.value) sum += normalizedRevenueCents(s.plan_id, intervalView.value);
    return sum;
});

const arpaCents = computed(() => {
    const act = activeSubs.value.length;
    return act ? Math.round(revenueCents.value / act) : 0;
});

// Health UI
const healthSeverity = computed(() => {
    if (loading.value) return 'secondary';
    return totalMismatches.value > 0 ? 'danger' : 'success';
});
const healthLabel = computed(() => {
    if (loading.value) return 'carregando';
    return totalMismatches.value > 0 ? 'atenção' : 'ok';
});
const healthHint = computed(() => {
    if (totalMismatches.value <= 0) return 'Tudo consistente: plano esperado = entitlements atuais.';
    return 'Há divergências entre o plano esperado e os entitlements atuais.';
});

// ------------------------------------
// Breakdown por plano
// ------------------------------------
const breakdown = computed(() => {
    const planById = new Map((plans.value || []).map((p) => [p.id, p]));
    const agg = new Map();

    for (const s of subs.value || []) {
        const p = planById.get(s.plan_id);
        const key = p?.key || '(sem plano)';

        if (!agg.has(key)) {
            agg.set(key, {
                plan_id: s.plan_id,
                plan_key: key,
                plan_target: p?.target || null,
                plan_active: p?.is_active !== false,
                active_count: 0,
                canceled_count: 0,
                price_cents: normalizedRevenueCents(s.plan_id, intervalView.value),
                revenue_cents: 0
            });
        }

        const row = agg.get(key);

        if (String(s.status) === 'active') {
            row.active_count += 1;
            row.revenue_cents += normalizedRevenueCents(s.plan_id, intervalView.value);
        } else if (String(s.status) === 'canceled') {
            row.canceled_count += 1;
        }
    }

    const out = Array.from(agg.values());
    out.sort((a, b) => b.revenue_cents - a.revenue_cents);
    return out;
});

// Chart
const chartData = computed(() => {
    const labels = breakdown.value.map((r) => r.plan_key);
    const data = breakdown.value.map((r) => Math.round((r.revenue_cents || 0) / 100));
    return {
        labels,
        datasets: [
            {
                label: intervalView.value === 'year' ? 'ARR por plano (R$)' : 'MRR por plano (R$)',
                data
            }
        ]
    };
});

const chartOptions = computed(() => ({
    maintainAspectRatio: false,
    plugins: {
        legend: { display: true },
        tooltip: { mode: 'index', intersect: false }
    },
    scales: { y: { beginAtZero: true } }
}));

// ------------------------------------
// Navegação
// ------------------------------------
function openPlanPublic(planKey) {
    if (!planKey || planKey === '(sem plano)') return;
    router.push({ path: '/saas/plans-public', query: { q: planKey } });
}

function openPlanCatalog(planKey) {
    if (!planKey || planKey === '(sem plano)') return;
    router.push({ path: '/saas/plans', query: { q: planKey } });
}

function openIntentEvents() {
    router.push('/saas/subscription-events');
}

// ------------------------------------
// Fetch
// ------------------------------------
async function loadIntents() {
    intentsLoading.value = true;
    try {
        const { data, error } = await supabase.from('subscription_intents').select('created_at,email,plan_key,interval,status,tenant_id').order('created_at', { ascending: false }).limit(intentsLimit.value);

        if (error) throw error;
        intents.value = data || [];

        const [{ count: cAll, error: eAll }, { count: cNew, error: eNew }, { count: cPaid, error: ePaid }] = await Promise.all([
            supabase.from('subscription_intents').select('id', { count: 'exact', head: true }),
            supabase.from('subscription_intents').select('id', { count: 'exact', head: true }).eq('status', 'new'),
            supabase.from('subscription_intents').select('id', { count: 'exact', head: true }).eq('status', 'paid')
        ]);

        if (eAll) throw eAll;
        if (eNew) throw eNew;
        if (ePaid) throw ePaid;

        totalIntents.value = Number(cAll || 0);
        totalIntentsNew.value = Number(cNew || 0);
        totalIntentsPaid.value = Number(cPaid || 0);
    } catch (e) {
        logError('SaasDashboard', 'loadIntents failed', e);
        intents.value = [];
        totalIntents.value = 0;
        totalIntentsNew.value = 0;
        totalIntentsPaid.value = 0;
    } finally {
        intentsLoading.value = false;
    }
}

async function loadStats() {
    loading.value = true;
    try {
        const [{ data: p, error: ep }, { data: ap, error: eap }, { data: s, error: es }] = await Promise.all([
            supabase.from('plans').select('id,key,target,is_active').order('key', { ascending: true }),
            supabase.from('v_plan_active_prices').select('*'),
            supabase.from('subscriptions').select('id,tenant_id,user_id,plan_id,status,updated_at').order('updated_at', { ascending: false })
        ]);

        if (ep) throw ep;
        if (eap) throw eap;
        if (es) throw es;

        plans.value = p || [];
        prices.value = ap || [];
        subs.value = s || [];

        totalActive.value = (subs.value || []).filter((x) => x.status === 'active').length;
        totalCanceled.value = (subs.value || []).filter((x) => x.status === 'canceled').length;

        const { data: mismatches, error: em } = await supabase.from('v_subscription_feature_mismatch').select('*');

        if (em) throw em;
        totalMismatches.value = (mismatches || []).length;

        await loadIntents();

        lastUpdatedAt.value = new Date().toISOString();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 5200 });
    } finally {
        loading.value = false;
    }
}

// ------------------------------------
// Fix all (com confirmação)
// ------------------------------------
function askFixAll() {
    if (loading.value) return;
    if (totalMismatches.value <= 0) return;

    confirm.require({
        header: 'Confirmar correção geral',
        message: `Reconstruir entitlements para todos os owners com divergência?\nTotal atual: ${totalMismatches.value}`,
        icon: 'pi pi-exclamation-triangle',
        acceptLabel: 'Corrigir agora',
        rejectLabel: 'Voltar',
        acceptClass: 'p-button-danger',
        accept: () => fixAll()
    });
}

async function fixAll() {
    loading.value = true;
    try {
        const { error } = await supabase.rpc('fix_all_subscription_mismatches');
        if (error) throw error;

        toast.add({
            severity: 'success',
            summary: 'Sistema corrigido',
            detail: 'Entitlements reconstruídos com sucesso.',
            life: 3200
        });

        await loadStats();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || String(e), life: 5200 });
    } finally {
        loading.value = false;
    }
}

// ------------------------------------
// Hero sticky
// ------------------------------------
const heroRef = ref(null);
const sentinelRef = ref(null);
const heroStuck = ref(false);
let heroObserver = null;
const mobileMenuRef = ref(null);

const heroMenuItems = computed(() => [
    {
        label: 'Recarregar',
        icon: 'pi pi-refresh',
        command: loadStats,
        disabled: loading.value
    },
    {
        label: 'Assinaturas',
        icon: 'pi pi-credit-card',
        command: () => router.push('/saas/subscriptions'),
        disabled: loading.value
    },
    {
        label: 'Eventos',
        icon: 'pi pi-history',
        command: () => router.push('/saas/subscription-events'),
        disabled: loading.value
    },
    { separator: true },
    {
        label: 'Intervalo',
        items: intervalOptions.map((o) => ({
            label: o.label,
            icon: intervalView.value === o.value ? 'pi pi-check' : 'pi pi-circle',
            command: () => {
                intervalView.value = o.value;
            }
        }))
    }
]);

onMounted(() => {
    loadStats();

    if (sentinelRef.value) {
        heroObserver = new IntersectionObserver(
            ([entry]) => {
                heroStuck.value = !entry.isIntersecting;
            },
            { rootMargin: `${document.querySelector('.l2-main') ? '0px' : '-56px'} 0px 0px 0px`, threshold: 0 }
        );
        heroObserver.observe(sentinelRef.value);
    }
});

onBeforeUnmount(() => {
    heroObserver?.disconnect();
});
</script>

<template>
    <ConfirmDialog />

    <!-- Sentinel -->
    <div ref="sentinelRef" class="h-px" />

    <!-- Hero sticky -->
    <div ref="heroRef" class="sticky mx-3 md:mx-4 mt-4 mb-4 z-20 overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5" :style="{ top: 'var(--layout-sticky-top, 56px)' }">
        <div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
            <div class="absolute rounded-full blur-[70px] w-72 h-72 -top-16 -right-20 bg-indigo-400/10" />
            <div class="absolute rounded-full blur-[70px] w-80 h-80 top-10 -left-24 bg-emerald-400/10" />
            <div class="absolute rounded-full blur-[70px] w-72 h-72 -bottom-20 right-24 bg-fuchsia-400/10" />
        </div>
        <div class="relative z-10 flex items-center justify-between gap-3 flex-wrap">
            <div class="min-w-0">
                <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">Central de Controle do SaaS</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Visão estratégica (receita e distribuição) + saúde de consistência (entitlements).</div>
            </div>

            <!-- desktop actions -->
            <div class="hidden xl:flex items-center gap-2 shrink-0">
                <SelectButton v-model="intervalView" :options="intervalOptions" optionLabel="label" optionValue="value" :disabled="loading" />
                <Button label="Recarregar" icon="pi pi-refresh" severity="secondary" outlined :loading="loading" @click="loadStats" />
                <Button label="Assinaturas" icon="pi pi-credit-card" severity="secondary" outlined :disabled="loading" @click="router.push('/saas/subscriptions')" />
                <Button label="Eventos" icon="pi pi-history" severity="secondary" outlined :disabled="loading" @click="router.push('/saas/subscription-events')" />
            </div>

            <!-- mobile -->
            <div class="flex xl:hidden shrink-0">
                <Button label="Ações" icon="pi pi-ellipsis-v" severity="warn" outlined @click="(e) => mobileMenuRef.toggle(e)" />
                <Menu ref="mobileMenuRef" :model="heroMenuItems" popup />
            </div>
        </div>
    </div>

    <!-- content -->
    <div class="px-3 md:px-4 pb-8 flex flex-col gap-4">
        <!-- KPIs -->
        <div class="grid grid-cols-12 gap-4">
            <div class="col-span-12 md:col-span-3">
                <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 h-full">
                    <div class="flex items-center justify-between mb-3">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">Ativas</div>
                        <Tag value="active" severity="success" rounded />
                    </div>
                    <div class="text-4xl font-semibold">{{ totalActive }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1">assinaturas em status <b>active</b></div>
                </div>
            </div>

            <div class="col-span-12 md:col-span-3">
                <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 h-full">
                    <div class="flex items-center justify-between mb-3">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">Canceladas</div>
                        <Tag value="canceled" severity="danger" rounded />
                    </div>
                    <div class="text-4xl font-semibold">{{ totalCanceled }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1">assinaturas em status <b>canceled</b></div>
                </div>
            </div>

            <div class="col-span-12 md:col-span-3">
                <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 h-full">
                    <div class="flex items-center justify-between mb-3">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">{{ intervalView === 'year' ? 'ARR' : 'MRR' }}</div>
                        <Tag :value="intervalView === 'year' ? 'anual' : 'mensal'" severity="secondary" rounded />
                    </div>
                    <div class="text-3xl font-semibold">{{ moneyBRLFromCents(revenueCents) }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1">normalizado (mensal ↔ anual)</div>
                </div>
            </div>

            <div class="col-span-12 md:col-span-3">
                <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 h-full">
                    <div class="flex items-center justify-between mb-3">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">ARPA</div>
                        <Tag value="média" severity="secondary" rounded />
                    </div>
                    <div class="text-3xl font-semibold">{{ moneyBRLFromCents(arpaCents) }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1">média por assinatura ativa</div>
                </div>
            </div>
        </div>

        <!-- Intenções + Health + Chart -->
        <div class="grid grid-cols-12 gap-4">
            <!-- Intenções -->
            <div class="col-span-12 md:col-span-4">
                <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 h-full">
                    <div class="flex items-center justify-between mb-3">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">Intenções de assinatura</div>
                        <Tag :value="intentsLoading ? 'carregando' : 'últimas'" severity="secondary" rounded />
                    </div>

                    <div class="grid grid-cols-12 gap-3">
                        <div class="col-span-4 rounded-md border border-[var(--surface-border)] p-3">
                            <div class="text-[1rem] text-[var(--text-color-secondary)]">Total</div>
                            <div class="text-2xl font-semibold">{{ totalIntents }}</div>
                        </div>
                        <div class="col-span-4 rounded-md border border-[var(--surface-border)] p-3">
                            <div class="text-[1rem] text-[var(--text-color-secondary)]">New</div>
                            <div class="text-2xl font-semibold">{{ totalIntentsNew }}</div>
                        </div>
                        <div class="col-span-4 rounded-md border border-[var(--surface-border)] p-3">
                            <div class="text-[1rem] text-[var(--text-color-secondary)]">Paid</div>
                            <div class="text-2xl font-semibold">{{ totalIntentsPaid }}</div>
                        </div>
                    </div>

                    <Divider class="my-3" />

                    <div v-if="intentsLoading" class="text-[1rem] text-[var(--text-color-secondary)]">Carregando intenções…</div>

                    <div v-else>
                        <div v-if="!intents.length" class="text-[1rem] text-[var(--text-color-secondary)]">Nenhuma intenção encontrada.</div>

                        <div v-else class="space-y-2">
                            <div v-for="(it, idx) in intents" :key="idx" class="flex items-start justify-between gap-3 rounded-md border border-[var(--surface-border)] p-3">
                                <div class="min-w-0">
                                    <div class="font-medium truncate">
                                        {{ maskEmail(it.email) }}
                                    </div>
                                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1">
                                        {{ it.plan_key || '—' }} • {{ intervalLabel(it.interval) }} •
                                        <span class="font-mono">{{ it.tenant_id ? String(it.tenant_id).slice(0, 8) + '…' : '—' }}</span>
                                    </div>
                                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-1">
                                        {{ fmtDate(it.created_at) }}
                                    </div>
                                </div>

                                <div class="shrink-0">
                                    <Tag :value="it.status || '—'" :severity="statusSeverity(it.status)" rounded />
                                </div>
                            </div>
                        </div>

                        <div class="flex gap-2 flex-wrap mt-3">
                            <Button label="Atualizar" icon="pi pi-refresh" severity="secondary" outlined size="small" :loading="intentsLoading || loading" @click="loadIntents" />
                            <Button label="Ver eventos" icon="pi pi-history" severity="secondary" outlined size="small" :disabled="loading" @click="openIntentEvents" />
                        </div>

                        <div class="text-[1rem] text-[var(--text-color-secondary)] mt-3">Mostrando {{ intentsLimit }} itens mais recentes de <span class="font-mono">subscription_intents</span>.</div>
                    </div>
                </div>
            </div>

            <!-- Health -->
            <div class="col-span-12 md:col-span-4">
                <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 h-full">
                    <div class="flex items-center justify-between mb-3">
                        <div class="text-[1rem] font-semibold text-[var(--text-color)]">Saúde do sistema</div>
                        <Tag :severity="healthSeverity" :value="healthLabel" rounded />
                    </div>

                    <div class="flex items-center justify-between gap-2">
                        <div class="text-4xl font-semibold">{{ totalMismatches }}</div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)] text-right">divergências entre plano (esperado) e entitlements (atual)</div>
                    </div>

                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-2">
                        {{ healthHint }}
                    </div>

                    <Divider class="my-3" />

                    <div class="flex gap-2 flex-wrap">
                        <Button v-if="totalMismatches > 0" label="Corrigir tudo" icon="pi pi-refresh" severity="danger" :loading="loading" @click="askFixAll" />
                        <Button label="Ver divergências" icon="pi pi-search" severity="secondary" outlined :disabled="loading" @click="router.push('/saas/subscription-health')" />
                    </div>

                    <div class="text-[1rem] text-[var(--text-color-secondary)] mt-3" v-if="lastUpdatedAt">Atualizado em {{ fmtDate(lastUpdatedAt) }}</div>
                </div>
            </div>

            <!-- Chart -->
            <div class="col-span-12 md:col-span-4">
                <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5 h-full">
                    <div class="text-[1rem] font-semibold text-[var(--text-color)] mb-3">{{ intervalView === 'year' ? 'ARR por plano' : 'MRR por plano' }}</div>
                    <div style="height: 260px">
                        <Chart type="bar" :data="chartData" :options="chartOptions" />
                    </div>
                </div>
            </div>
        </div>

        <!-- Receita de créditos WhatsApp (Asaas) -->
        <SaasCreditsRevenueCard />

        <!-- Breakdown table (com ações) -->
        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
            <div class="text-[1rem] font-semibold text-[var(--text-color)] mb-3">Distribuição por plano</div>
            <DataTable :value="breakdown" stripedRows responsiveLayout="scroll" emptyMessage="Sem dados para exibir.">
                <Column field="plan_key" header="Plano" style="min-width: 14rem">
                    <template #body="{ data }">
                        <div class="flex flex-col">
                            <span class="font-medium">{{ data.plan_key }}</span>
                            <div class="text-[1rem] text-[var(--text-color-secondary)]">
                                {{ data.plan_active ? 'ativo no catálogo' : 'inativo no catálogo' }}
                            </div>
                        </div>
                    </template>
                </Column>

                <Column header="Público" style="width: 12rem">
                    <template #body="{ data }">
                        <Tag :value="planTargetLabel(data.plan_target)" :severity="planTargetSeverity(data.plan_target)" rounded />
                    </template>
                </Column>

                <Column header="Ativas" style="width: 8rem">
                    <template #body="{ data }">{{ data.active_count }}</template>
                </Column>

                <Column header="Canceladas" style="width: 10rem">
                    <template #body="{ data }">{{ data.canceled_count }}</template>
                </Column>

                <Column header="Preço (ref.)" style="min-width: 12rem">
                    <template #body="{ data }">{{ moneyBRLFromCents(data.price_cents) }}</template>
                </Column>

                <Column :header="intervalView === 'year' ? 'ARR' : 'MRR'" style="min-width: 12rem">
                    <template #body="{ data }">{{ moneyBRLFromCents(data.revenue_cents) }}</template>
                </Column>

                <Column header="Ações" style="width: 16rem">
                    <template #body="{ data }">
                        <div class="flex gap-2 justify-end flex-wrap">
                            <Button label="Abrir vitrine" icon="pi pi-external-link" severity="secondary" outlined size="small" :disabled="!data.plan_key || data.plan_key === '(sem plano)'" @click="openPlanPublic(data.plan_key)" />
                            <Button
                                icon="pi pi-pencil"
                                severity="secondary"
                                outlined
                                size="small"
                                :disabled="!data.plan_key || data.plan_key === '(sem plano)'"
                                v-tooltip.top="'Abrir catálogo interno do plano'"
                                @click="openPlanCatalog(data.plan_key)"
                            />
                        </div>
                    </template>
                </Column>
            </DataTable>

            <div class="text-[1rem] text-[var(--text-color-secondary)] mt-3">Nota: "Preço (ref.)" e "MRR/ARR" são normalizados usando o preço ativo. Se só existir anual, MRR = anual/12; se só existir mensal, ARR = mensal*12.</div>
        </div>
    </div>
</template>
