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

import Dropdown from 'primevue/dropdown';
import Textarea from 'primevue/textarea';

import { supabase } from '@/lib/supabase/client';
import { logError } from '@/support/supportLogger';

const TAG = 'SubscriptionIntentsPage';

import { listSubscriptionIntents, markIntentPaid, cancelIntent, getSubscriptionForIntent } from '@/services/subscriptionIntents';

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

// ---------------------------------------
// State
// ---------------------------------------
const loading = ref(false);
const isFetching = ref(false);
const acting = ref(false);

const rows = ref([]);

// filtros (UI)
const q = ref('');
const status = ref(null);
const planKey = ref(null);
const interval = ref(null);

// dialog intenção
const showDialog = ref(false);
const selected = ref(null);
const actionMode = ref(null); // 'paid' | 'canceled'
const notes = ref('');

// dialog assinatura
const showSubDialog = ref(false);
const selectedSub = ref(null);
const subActionMode = ref(null);
const subNotes = ref('');

// UX
const lastRefreshAt = ref(null);
const hasAnyFilter = computed(() => !!(q.value || status.value || planKey.value || interval.value));

// ---------------------------------------
// Options
// ---------------------------------------
const statusOptions = [
    { label: 'Novo', value: 'new' },
    { label: 'Aguardando pagamento', value: 'waiting_payment' },
    { label: 'Pago', value: 'paid' },
    { label: 'Cancelado', value: 'canceled' }
];

const intervalOptions = [
    { label: 'Mensal', value: 'month' },
    { label: 'Anual', value: 'year' }
];

const planOptions = computed(() => {
    const keys = Array.from(new Set((rows.value || []).map((r) => r.plan_key).filter(Boolean)));
    keys.sort((a, b) => String(a).localeCompare(String(b)));
    return keys.map((k) => ({ label: k, value: k }));
});

// ---------------------------------------
// Helpers
// ---------------------------------------
function moneyBRL(cents) {
    if (cents == null) return '—';
    return (Number(cents) / 100).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
}

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 statusSeverity(s) {
    if (s === 'paid') return 'success';
    if (s === 'new') return 'info';
    if (s === 'waiting_payment') return 'warning';
    if (s === 'canceled') return 'danger';
    return 'secondary';
}

function statusLabel(s) {
    if (s === 'new') return 'Novo';
    if (s === 'waiting_payment') return 'Aguardando pagamento';
    if (s === 'paid') return 'Pago';
    if (s === 'canceled') return 'Cancelado';
    return String(s || '—');
}

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

function diagChips(row) {
    const chips = [];
    const target = String(row?.plan_target || '').toLowerCase();

    if (target) chips.push({ label: target === 'clinic' ? 'Clínica' : target === 'therapist' ? 'Terapeuta' : target, severity: target === 'clinic' ? 'info' : target === 'therapist' ? 'success' : 'secondary' });
    if (target === 'clinic' && !row?.tenant_id) chips.push({ label: 'Sem tenant_id', severity: 'danger' });
    return chips;
}

function subStatusLabel(s) {
    if (s === 'pending') return 'Pendente';
    if (s === 'active') return 'Ativa';
    if (s === 'past_due') return 'Em atraso';
    if (s === 'suspended') return 'Suspensa';
    if (s === 'cancelled') return 'Cancelada';
    if (s === 'expired') return 'Expirada';
    return String(s || '—');
}

function subStatusSeverity(s) {
    if (s === 'active') return 'success';
    if (s === 'pending') return 'info';
    if (s === 'past_due') return 'warning';
    if (s === 'suspended') return 'danger';
    if (s === 'cancelled') return 'secondary';
    if (s === 'expired') return 'secondary';
    return 'secondary';
}

function canReactivateSubscription(sub) {
    if (!sub) return false;
    if (sub.status !== 'cancelled') return false;
    if (!sub.current_period_end) return false;
    const end = new Date(sub.current_period_end);
    if (Number.isNaN(end.getTime())) return false;
    return new Date() < end;
}

// ---------------------------------------
// Preflight
// ---------------------------------------
function preflightIntent(row, mode) {
    if (!row) return { ok: false, msg: 'Linha inválida.' };

    if (mode === 'paid') {
        if (row.status === 'paid') return { ok: false, msg: 'Essa intenção já está como paga.' };
        if (row.status === 'canceled') return { ok: false, msg: 'Intenção cancelada não pode ser marcada como paga.' };

        const target = String(row.plan_target || '').toLowerCase();
        const isClinicTarget = target ? target === 'clinic' : true;

        if (isClinicTarget && !row.tenant_id) {
            return { ok: false, msg: 'Plano de clínica exige tenant_id, mas esta intenção está sem tenant_id.' };
        }
    }

    if (mode === 'canceled') {
        if (row.status === 'canceled') return { ok: false, msg: 'Essa intenção já está cancelada.' };
    }

    return { ok: true, msg: '' };
}

function preflightSubscription(sub, mode) {
    if (!sub) return { ok: false, msg: 'Assinatura inválida.' };

    if (mode === 'reactivate') {
        if (!canReactivateSubscription(sub)) {
            return { ok: false, msg: 'Reabilitação não permitida: assinatura não está cancelada ou o período já terminou.' };
        }
    }

    if (mode === 'cancel') {
        if (sub.status === 'cancelled') return { ok: false, msg: 'Assinatura já está cancelada.' };
        if (sub.status === 'expired') return { ok: false, msg: 'Assinatura expirada não pode ser cancelada (crie uma nova).' };
    }

    if (mode === 'suspend') {
        if (sub.status === 'suspended') return { ok: false, msg: 'Assinatura já está suspensa.' };
        if (sub.status === 'expired') return { ok: false, msg: 'Assinatura expirada não pode ser suspensa.' };
    }

    if (mode === 'mark_past_due') {
        if (sub.status === 'past_due') return { ok: false, msg: 'Assinatura já está em atraso.' };
        if (sub.status !== 'active') return { ok: false, msg: 'Marcar como atraso faz sentido apenas para assinaturas ativas.' };
    }

    if (mode === 'expire') {
        if (sub.status === 'expired') return { ok: false, msg: 'Assinatura já está expirada.' };
    }

    return { ok: true, msg: '' };
}

// ---------------------------------------
// Fetch
// ---------------------------------------
async function refresh() {
    if (isFetching.value) return;
    isFetching.value = true;
    loading.value = true;

    try {
        rows.value = await listSubscriptionIntents({
            q: q.value,
            status: status.value,
            planKey: planKey.value,
            interval: interval.value
        });
        lastRefreshAt.value = new Date().toISOString();
    } catch (e) {
        logError(TAG, 'refresh', e);
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao carregar.', life: 4500 });
    } finally {
        loading.value = false;
        isFetching.value = false;
    }
}

function clearFilters() {
    if (acting.value) return;
    q.value = '';
    status.value = null;
    planKey.value = null;
    interval.value = null;
    refresh();
}

watch([status, planKey, interval], () => {
    if (!lastRefreshAt.value) return;
    refresh();
});

// ---------------------------------------
// Filtro frontend
// ---------------------------------------
const filteredRows = computed(() => {
    let list = rows.value || [];

    const term = String(q.value || '')
        .trim()
        .toLowerCase();
    if (term) {
        list = list.filter(
            (r) =>
                String(r.email || '')
                    .toLowerCase()
                    .includes(term) ||
                String(r.plan_key || '')
                    .toLowerCase()
                    .includes(term) ||
                String(r.tenant_id || '')
                    .toLowerCase()
                    .includes(term)
        );
    }

    if (status.value) list = list.filter((r) => String(r.status || '') === String(status.value));
    if (interval.value) list = list.filter((r) => String(r.interval || '') === String(interval.value));
    if (planKey.value) list = list.filter((r) => String(r.plan_key || '') === String(planKey.value));

    return list;
});

const totals = computed(() => {
    const list = filteredRows.value || [];
    const by = (s) => list.filter((r) => r.status === s).length;
    return {
        total: list.length,
        new: by('new'),
        waiting: by('waiting_payment'),
        paid: by('paid'),
        canceled: by('canceled')
    };
});

// ---------------------------------------
// Intent Dialog + Actions
// ---------------------------------------
function openAction(row, mode) {
    const pf = preflightIntent(row, mode);
    if (!pf.ok) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: pf.msg, life: 4200 });
        return;
    }

    selected.value = row;
    actionMode.value = mode;
    notes.value = '';
    showDialog.value = true;
}

function closeDialog() {
    if (acting.value) return;
    showDialog.value = false;
}

function askConfirmAction() {
    if (!selected.value || !actionMode.value) return;
    if (acting.value) return;

    const pf = preflightIntent(selected.value, actionMode.value);
    if (!pf.ok) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: pf.msg, life: 4200 });
        return;
    }

    const isPaid = actionMode.value === 'paid';
    const verb = isPaid ? 'marcar como PAGO' : 'CANCELAR';
    const sev = isPaid ? 'success' : 'danger';
    const acceptLabel = isPaid ? 'Confirmar pagamento' : 'Confirmar cancelamento';

    confirm.require({
        header: 'Confirmar ação',
        icon: 'pi pi-exclamation-triangle',
        message: `Você realmente deseja ${verb} esta intenção?\n\n${selected.value.email}\nPlano: ${selected.value.plan_key} • ${intervalLabel(selected.value.interval)} • ${moneyBRL(selected.value.amount_cents)}`,
        acceptLabel,
        rejectLabel: 'Voltar',
        acceptClass: sev === 'danger' ? 'p-button-danger' : '',
        accept: () => confirmAction()
    });
}

async function confirmAction() {
    if (!selected.value || !actionMode.value) return;
    if (acting.value) return;

    const pf = preflightIntent(selected.value, actionMode.value);
    if (!pf.ok) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: pf.msg, life: 4200 });
        return;
    }

    acting.value = true;

    try {
        if (actionMode.value === 'paid') {
            const res = await markIntentPaid(selected.value.id, notes.value);

            const plan = res?.subscription?.plan_key || selected.value.plan_key || '—';
            const itv = res?.subscription?.interval || selected.value.interval;
            const itvLbl = intervalLabel(itv);

            toast.add({
                severity: 'success',
                summary: 'Pagamento confirmado',
                detail: `Assinatura ativada: ${plan} (${itvLbl}).`,
                life: 3200
            });
        } else if (actionMode.value === 'canceled') {
            await cancelIntent(selected.value.id, notes.value);
            toast.add({ severity: 'warn', summary: 'Cancelado', detail: 'A intenção foi cancelada.', life: 2800 });
        }

        showDialog.value = false;
        await refresh();
    } catch (e) {
        logError(TAG, 'confirmAction', e);

        const msg = e?.message || 'Falha ao atualizar.';
        const msgLower = String(msg).toLowerCase();

        const hint =
            msgLower.includes('tenant_id') && msgLower.includes('therapist')
                ? 'Dica: therapist NÃO deve ter tenant_id.'
                : msgLower.includes('tenant_id')
                  ? 'Dica: confirme tenant_id (plan_target=clinic exige).'
                  : msgLower.includes('target')
                    ? 'Dica: verifique plans.target e validações/trigger do escopo.'
                    : msgLower.includes('paid')
                      ? 'Dica: confirme o status atual antes de ativar.'
                      : '';

        toast.add({
            severity: 'error',
            summary: 'Erro',
            detail: hint ? `${msg} — ${hint}` : msg,
            life: 5200
        });
    } finally {
        acting.value = false;
    }
}

// ---------------------------------------
// Subscription Actions (via RPC)
// ---------------------------------------
async function fetchSubscription(subscriptionId) {
    const { data, error } = await supabase.from('subscriptions').select('*').eq('id', subscriptionId).maybeSingle();

    if (error) throw error;
    if (!data) throw new Error('Assinatura não encontrada.');
    return data;
}

async function transitionSubscription(subscriptionId, toStatus, reason) {
    const { data, error } = await supabase.rpc('transition_subscription', {
        p_subscription_id: subscriptionId,
        p_to_status: toStatus,
        p_reason: reason || null,
        p_metadata: { source: 'manual_intents_inbox_ui' }
    });

    if (error) throw error;
    return data;
}

async function openSubscriptionDialogFromIntent(intentRow) {
    if (!intentRow?.id) return;
    if (acting.value) return;

    acting.value = true;

    try {
        const sub = await getSubscriptionForIntent(intentRow, { strictPlanKey: true, onlyActive: false });

        if (!sub?.id) {
            toast.add({
                severity: 'info',
                summary: 'Sem assinatura',
                detail: 'Nenhuma assinatura encontrada para esta intenção ainda.',
                life: 4200
            });
            return;
        }

        selectedSub.value = sub;
        subActionMode.value = null;
        subNotes.value = '';
        showSubDialog.value = true;
    } catch (e) {
        logError(TAG, 'openSubscriptionDialog', e);
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Falha ao carregar assinatura.', life: 4500 });
    } finally {
        acting.value = false;
    }
}

function closeSubDialog() {
    if (acting.value) return;
    showSubDialog.value = false;
}

function askConfirmSubAction(mode) {
    if (!selectedSub.value) return;
    if (acting.value) return;

    const pf = preflightSubscription(selectedSub.value, mode);
    if (!pf.ok) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: pf.msg, life: 4200 });
        return;
    }

    subActionMode.value = mode;

    const map = {
        cancel: { verb: 'CANCELAR', to: 'cancelled', sev: 'danger', label: 'Confirmar cancelamento' },
        suspend: { verb: 'SUSPENDER', to: 'suspended', sev: 'danger', label: 'Confirmar suspensão' },
        reactivate: { verb: 'REABILITAR', to: 'active', sev: 'success', label: 'Confirmar reabilitação' },
        mark_past_due: { verb: 'MARCAR COMO ATRASO', to: 'past_due', sev: 'warning', label: 'Confirmar atraso' },
        expire: { verb: 'EXPIRAR', to: 'expired', sev: 'danger', label: 'Confirmar expiração' }
    };

    const cfg = map[mode];
    if (!cfg) return;

    const sub = selectedSub.value;
    const details = [
        `Plano: ${sub.plan_key || '—'} • ${intervalLabel(sub.interval)} • Status: ${subStatusLabel(sub.status)}`,
        `Período: ${fmtDate(sub.current_period_start)} → ${fmtDate(sub.current_period_end)}`,
        sub.tenant_id ? `tenant_id: ${sub.tenant_id}` : null,
        `Assinatura: ${sub.id}`
    ]
        .filter(Boolean)
        .join('\n');

    confirm.require({
        header: 'Confirmar ação na assinatura',
        icon: 'pi pi-exclamation-triangle',
        message: `Você realmente deseja ${cfg.verb} esta assinatura?\n\n${details}`,
        acceptLabel: cfg.label,
        rejectLabel: 'Voltar',
        acceptClass: cfg.sev === 'danger' ? 'p-button-danger' : '',
        accept: () => confirmSubAction(cfg.to)
    });
}

async function confirmSubAction(toStatus) {
    if (!selectedSub.value) return;
    if (acting.value) return;

    const sub = selectedSub.value;
    const mode = subActionMode.value;
    const pf = preflightSubscription(sub, mode);
    if (!pf.ok) {
        toast.add({ severity: 'warn', summary: 'Atenção', detail: pf.msg, life: 4200 });
        return;
    }

    acting.value = true;

    try {
        const reason =
            subNotes.value ||
            (mode === 'reactivate'
                ? 'Desfazer cancelamento (janela do período)'
                : mode === 'cancel'
                  ? 'Cancelamento manual'
                  : mode === 'suspend'
                    ? 'Suspensão manual'
                    : mode === 'mark_past_due'
                      ? 'Marcação manual de atraso'
                      : mode === 'expire'
                        ? 'Expiração manual'
                        : null);

        const updated = await transitionSubscription(sub.id, toStatus, reason);

        selectedSub.value = updated;

        toast.add({
            severity: toStatus === 'active' ? 'success' : toStatus === 'past_due' ? 'warn' : 'info',
            summary: 'Assinatura atualizada',
            detail: `Novo status: ${subStatusLabel(updated?.status)}.`,
            life: 3200
        });

        await refresh();
    } catch (e) {
        logError(TAG, 'confirmSubAction', e);
        toast.add({
            severity: 'error',
            summary: 'Erro',
            detail: e?.message || 'Falha ao atualizar assinatura.',
            life: 5200
        });
    } finally {
        acting.value = false;
    }
}

// ── Hero sticky ────────────────────────────────────────────
const heroEl = ref(null);
const heroSentinelRef = ref(null);
const heroMenuRef = ref(null);
const heroStuck = ref(false);
let disconnectObserver = null;

const heroMenuItems = computed(() => [
    {
        label: 'Atualizar',
        icon: 'pi pi-refresh',
        command: refresh,
        disabled: loading.value || acting.value
    },
    ...(hasAnyFilter.value
        ? [
              {
                  label: 'Limpar filtros',
                  icon: 'pi pi-times',
                  command: clearFilters,
                  disabled: acting.value
              }
          ]
        : [])
]);

onMounted(async () => {
    await refresh();

    const sentinel = heroSentinelRef.value;
    if (sentinel) {
        const io = new IntersectionObserver(
            ([entry]) => {
                heroStuck.value = !entry.isIntersecting;
            },
            { rootMargin: `${document.querySelector('.l2-main') ? '0px' : '-56px'} 0px 0px 0px` }
        );
        io.observe(sentinel);
        disconnectObserver = () => io.disconnect();
    }
});

onBeforeUnmount(() => {
    try {
        disconnectObserver?.();
    } catch {}
});
</script>

<template>
    <ConfirmDialog />

    <div class="flex flex-col gap-4 p-4">
        <!-- Header -->
        <div class="cfg-subheader">
            <div class="cfg-subheader__icon"><i class="pi pi-inbox" /></div>
            <div class="min-w-0 flex-1">
                <div class="cfg-subheader__title">Intenções de assinatura</div>
                <div class="cfg-subheader__sub">Caixa de entrada de pagamento manual (PIX/boleto). Marque como pago para ativar ou cancele quando não for concluído.</div>
            </div>
            <div class="hidden xl:flex items-center gap-2 shrink-0">
                <Button label="Atualizar" icon="pi pi-refresh" severity="secondary" outlined size="small" :loading="loading" :disabled="acting" @click="refresh" />
                <Button v-if="hasAnyFilter" label="Limpar filtros" icon="pi pi-times" severity="secondary" outlined size="small" :disabled="acting" @click="clearFilters" />
            </div>
            <div class="flex xl:hidden shrink-0">
                <Button label="Ações" icon="pi pi-ellipsis-v" severity="warn" size="small" @click="(e) => heroMenuRef.toggle(e)" />
                <Menu ref="heroMenuRef" :model="heroMenuItems" popup />
            </div>
        </div>
        <!-- Card: Resumo + Filtros -->
        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5">
            <div class="flex items-center justify-between gap-3 flex-wrap mb-4">
                <div class="flex items-center gap-2">
                    <i class="pi pi-filter text-[var(--text-color-secondary)]" />
                    <div class="text-[1rem] font-semibold text-[var(--text-color)]">Busca &amp; Filtros</div>
                </div>
                <!-- contagens -->
                <div class="flex flex-wrap gap-2 items-center">
                    <Tag :value="`Total: ${totals.total}`" severity="secondary" rounded />
                    <Tag :value="`Novas: ${totals.new}`" severity="info" rounded />
                    <Tag :value="`Aguardando: ${totals.waiting}`" severity="warning" rounded />
                    <Tag :value="`Pagas: ${totals.paid}`" severity="success" rounded />
                    <Tag :value="`Canceladas: ${totals.canceled}`" severity="danger" rounded />
                    <div class="text-[1rem] text-[var(--text-color-secondary)]">
                        <template v-if="lastRefreshAt">· {{ fmtDate(lastRefreshAt) }}</template>
                    </div>
                </div>
            </div>

            <div class="grid grid-cols-12 gap-3">
                <!-- Busca -->
                <div class="col-span-12 md:col-span-5">
                    <FloatLabel variant="on" class="w-full">
                        <IconField class="w-full">
                            <InputIcon class="pi pi-search" />
                            <InputText v-model="q" id="si-search" class="w-full pr-10" variant="filled" :disabled="acting" placeholder="ex.: email@dominio.com" @keyup.enter="refresh" />
                        </IconField>
                        <label for="si-search">Buscar por e-mail / plano / tenant_id</label>
                    </FloatLabel>
                </div>

                <!-- Status -->
                <div class="col-span-12 md:col-span-3">
                    <FloatLabel variant="on" class="w-full">
                        <Dropdown v-model="status" :options="statusOptions" optionLabel="label" optionValue="value" class="w-full" showClear :disabled="acting" />
                        <label>Status</label>
                    </FloatLabel>
                </div>

                <!-- Intervalo -->
                <div class="col-span-12 md:col-span-2">
                    <FloatLabel variant="on" class="w-full">
                        <Dropdown v-model="interval" :options="intervalOptions" optionLabel="label" optionValue="value" class="w-full" showClear :disabled="acting" />
                        <label>Intervalo</label>
                    </FloatLabel>
                </div>

                <!-- Plano -->
                <div class="col-span-12 md:col-span-2">
                    <FloatLabel variant="on" class="w-full">
                        <Dropdown v-model="planKey" :options="planOptions" optionLabel="label" optionValue="value" class="w-full" showClear :disabled="acting" />
                        <label>Plano</label>
                    </FloatLabel>
                </div>

                <!-- Botões -->
                <div class="col-span-12 flex gap-2 flex-wrap">
                    <Button label="Aplicar" icon="pi pi-filter" @click="refresh" :disabled="acting" />
                    <Button v-if="hasAnyFilter" label="Limpar filtros" icon="pi pi-times" severity="secondary" outlined @click="clearFilters" :disabled="acting" />
                </div>
            </div>
        </div>

        <DataTable :value="filteredRows" :loading="loading" paginator :rows="20" :rowsPerPageOptions="[10, 20, 50]" responsiveLayout="scroll" sortField="created_at" :sortOrder="-1" emptyMessage="Nenhuma intenção encontrada para os filtros atuais.">
            <Column field="id" header="Intent ID" style="min-width: 18rem">
                <template #body="{ data }">
                    <div class="text-[1rem]">{{ data.id }}</div>
                </template>
            </Column>

            <Column field="email" header="E-mail" :sortable="true" style="min-width: 16rem" />

            <Column header="Plano" :sortable="true" sortField="plan_key" 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)]">{{ intervalLabel(data.interval) }} • {{ moneyBRL(data.amount_cents) }}</div>
                    </div>
                </template>
            </Column>

            <Column header="Contexto" style="min-width: 14rem">
                <template #body="{ data }">
                    <div class="flex flex-wrap gap-2 items-center">
                        <Tag v-for="c in diagChips(data)" :key="c.label" :severity="c.severity" :value="c.label" rounded />
                        <span v-if="!diagChips(data).length" class="text-[var(--text-color-secondary)]">—</span>
                    </div>
                    <div v-if="data.tenant_id" class="mt-1 text-[1rem] text-[var(--text-color-secondary)]">tenant_id: {{ data.tenant_id }}</div>
                </template>
            </Column>

            <Column field="status" header="Status" :sortable="true" style="width: 13rem">
                <template #body="{ data }">
                    <Tag :severity="statusSeverity(data.status)" :value="statusLabel(data.status)" />
                </template>
            </Column>

            <Column header="Ações" style="width: 24rem">
                <template #body="{ data }">
                    <div class="flex gap-2 flex-wrap justify-end">
                        <Button label="Pago" icon="pi pi-check" size="small" severity="success" :disabled="acting || loading || data.status === 'paid' || data.status === 'canceled'" @click="openAction(data, 'paid')" />
                        <Button label="Cancelar" icon="pi pi-times" size="small" severity="danger" outlined :disabled="acting || loading || data.status === 'canceled'" @click="openAction(data, 'canceled')" />
                        <Button label="Assinatura" icon="pi pi-cog" size="small" severity="secondary" outlined :disabled="acting || loading" @click="openSubscriptionDialogFromIntent(data)" />
                    </div>
                </template>
            </Column>
        </DataTable>
    </div>

    <!-- Dialog: intenção -->
    <Dialog v-model:visible="showDialog" modal :header="actionMode === 'paid' ? 'Confirmar pagamento' : 'Confirmar cancelamento'" :style="{ width: '560px' }" :closable="!acting" :dismissableMask="!acting" :draggable="false">
        <div v-if="selected" class="text-[1rem]">
            <div class="mb-3">
                <div class="font-semibold">{{ selected.email }}</div>
                <div class="text-[var(--text-color-secondary)]">Plano: {{ selected.plan_key }} • Intervalo: {{ intervalLabel(selected.interval) }} • Valor: {{ moneyBRL(selected.amount_cents) }}</div>
                <div class="text-[var(--text-color-secondary)] mt-1" v-if="selected.tenant_id">tenant_id: {{ selected.tenant_id }}</div>
            </div>

            <FloatLabel variant="on" class="w-full">
                <Textarea v-model="notes" rows="3" class="w-full" autoResize :disabled="acting" />
                <label>Notas internas (opcional)</label>
            </FloatLabel>

            <div class="flex justify-end gap-2 mt-4">
                <Button label="Voltar" severity="secondary" outlined @click="closeDialog" :disabled="acting" />
                <Button
                    :label="actionMode === 'paid' ? 'Marcar como pago' : 'Cancelar intenção'"
                    :icon="actionMode === 'paid' ? 'pi pi-check' : 'pi pi-times'"
                    :severity="actionMode === 'paid' ? 'success' : 'danger'"
                    @click="askConfirmAction"
                    :loading="acting"
                />
            </div>
        </div>
    </Dialog>

    <!-- Dialog: assinatura (via RPC) -->
    <Dialog v-model:visible="showSubDialog" modal header="Gerenciar assinatura" :style="{ width: '640px' }" :closable="!acting" :dismissableMask="!acting" :draggable="false">
        <div v-if="selectedSub" class="text-[1rem]">
            <div class="mb-3">
                <div class="flex items-center justify-between gap-3 flex-wrap">
                    <div>
                        <div class="font-semibold">{{ selectedSub.plan_key || '—' }} • {{ intervalLabel(selectedSub.interval) }}</div>
                        <div class="text-[var(--text-color-secondary)] mt-1">Período: {{ fmtDate(selectedSub.current_period_start) }} → {{ fmtDate(selectedSub.current_period_end) }}</div>
                        <div class="text-[var(--text-color-secondary)] mt-1">
                            owner(user_id): {{ selectedSub.user_id }}
                            <span v-if="selectedSub.tenant_id"> • tenant_id: {{ selectedSub.tenant_id }}</span>
                        </div>
                        <div class="text-[var(--text-color-secondary)] mt-1">subscription_id: {{ selectedSub.id }}</div>
                    </div>
                    <Tag :severity="subStatusSeverity(selectedSub.status)" :value="subStatusLabel(selectedSub.status)" />
                </div>
            </div>

            <FloatLabel variant="on" class="w-full">
                <Textarea v-model="subNotes" rows="3" class="w-full" autoResize :disabled="acting" />
                <label>Motivo / nota (opcional)</label>
            </FloatLabel>

            <Divider class="my-4" />

            <div class="flex justify-end gap-2 flex-wrap">
                <Button label="Fechar" severity="secondary" outlined @click="closeSubDialog" :disabled="acting" />
                <Button label="Marcar atraso" icon="pi pi-clock" severity="warning" outlined :disabled="acting || selectedSub.status !== 'active'" @click="askConfirmSubAction('mark_past_due')" />
                <Button label="Suspender" icon="pi pi-ban" severity="danger" outlined :disabled="acting || selectedSub.status === 'suspended' || selectedSub.status === 'expired'" @click="askConfirmSubAction('suspend')" />
                <Button label="Cancelar" icon="pi pi-times" severity="danger" :disabled="acting || selectedSub.status === 'cancelled' || selectedSub.status === 'expired'" @click="askConfirmSubAction('cancel')" />
                <Button v-if="canReactivateSubscription(selectedSub)" label="Reabilitar" icon="pi pi-refresh" severity="success" :disabled="acting" @click="askConfirmSubAction('reactivate')" />
                <Button label="Expirar" icon="pi pi-calendar-times" severity="danger" outlined :disabled="acting || selectedSub.status === 'expired'" @click="askConfirmSubAction('expire')" />
            </div>
        </div>
    </Dialog>
</template>