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

import { supabase } from '@/lib/supabase/client';
import { tenantDb } from '@/lib/supabase/tenantClient';
import { useTenantStore } from '@/stores/tenantStore';
import { useFinancialRecords } from '@/composables/useFinancialRecords';

// ─── composable ──────────────────────────────────────────────────────────────
const { records, loading, error, summary, fetchRecords, markAsPaid, cancelRecord, createManualRecord } = useFinancialRecords();

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

// ─── sticky hero ─────────────────────────────────────────────────────────────
const headerSentinelRef = ref(null);
const headerEl = ref(null);
const headerStuck = ref(false);
let _observer = null;

// ─── controle de carregamento ─────────────────────────────────────────────────
const hasLoaded = ref(false);
const mounted = ref(false);

// ─── pacientes para o filtro ─────────────────────────────────────────────────
const patients = ref([]);

async function loadPatients() {
    const tenantStore = useTenantStore();
    const tenantId = tenantStore.activeTenantId;
    if (!tenantId) return;

    const { data } = await tenantDb().from('patients').select('id, nome_completo, identification_color').order('nome_completo');
    patients.value = data ?? [];
}

// ─── opções de filtro e formulário ───────────────────────────────────────────
const STATUS_OPTIONS = [
    { label: 'Todos', value: null },
    { label: 'Pendente', value: 'pending' },
    { label: 'Vencido', value: 'overdue' },
    { label: 'Pago', value: 'paid' },
    { label: 'Cancelado', value: 'cancelled' }
];

const PAYMENT_METHOD_OPTIONS = [
    { label: 'Pix', value: 'pix' },
    { label: 'Depósito', value: 'deposito' },
    { label: 'Dinheiro', value: 'dinheiro' },
    { label: 'Cartão', value: 'cartao' },
    { label: 'Convênio', value: 'convenio' }
];

function paymentLabel(method) {
    return PAYMENT_METHOD_OPTIONS.find((o) => o.value === method)?.label ?? method ?? '—';
}

const TYPE_OPTIONS = [
    { label: 'Todos', value: null },
    { label: 'Receita', value: 'receita' },
    { label: 'Despesa', value: 'despesa' }
];

// ─── filtros reativos ─────────────────────────────────────────────────────────
const filterStatus = ref(null);
const filterType = ref(null);
const filterPatient = ref(null);
const filterDateRange = ref(null);

// ─── paginação server-side ────────────────────────────────────────────────────
const pageFirst = ref(0);
const pageRows = ref(20);
const totalRecords = ref(0);

const hasActiveFilters = computed(() => filterStatus.value !== null || filterType.value !== null || filterPatient.value !== null || filterDateRange.value !== null);

function clearFilters() {
    filterStatus.value = null;
    filterType.value = null;
    filterPatient.value = null;
    filterDateRange.value = null;
    pageFirst.value = 0;
}

async function applyFilters(resetPage = true) {
    if (resetPage) pageFirst.value = 0;
    const f = {
        limit: pageRows.value,
        offset: pageFirst.value
    };
    if (filterStatus.value) f.status = filterStatus.value;
    if (filterType.value) f.type = filterType.value;
    if (filterPatient.value) f.patient_id = filterPatient.value.id;
    if (filterDateRange.value) {
        const [from, to] = filterDateRange.value;
        if (from) f.due_date_from = from instanceof Date ? from.toISOString().slice(0, 10) : from;
        if (to) f.due_date_to = to instanceof Date ? to.toISOString().slice(0, 10) : to;
    }
    const result = await fetchRecords(f);
    totalRecords.value = result?.total ?? records.value.length;
    hasLoaded.value = true;
}

async function onPageChange(e) {
    pageFirst.value = e.first;
    pageRows.value = e.rows;
    await applyFilters(false);
}

watch([filterStatus, filterType, filterPatient, filterDateRange], () => applyFilters(true), { deep: true });

// ─── formatação ───────────────────────────────────────────────────────────────
const _brl = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });

function fmtBRL(v) {
    return _brl.format(v ?? 0);
}

function fmtDate(iso) {
    if (!iso) return '—';
    // Adiciona T00:00:00 para forçar timezone local em strings date-only
    const d = iso.includes('T') ? new Date(iso) : new Date(iso + 'T00:00:00');
    return new Intl.DateTimeFormat('pt-BR').format(d);
}

function fmtDateTime(iso) {
    if (!iso) return null;
    return new Intl.DateTimeFormat('pt-BR', {
        day: '2-digit',
        month: '2-digit',
        year: 'numeric',
        hour: '2-digit',
        minute: '2-digit'
    }).format(new Date(iso));
}

function isOverdueDate(dueDateIso) {
    if (!dueDateIso) return false;
    return new Date(dueDateIso + 'T00:00:00') < new Date(new Date().toDateString());
}

// ─── config visual de status ──────────────────────────────────────────────────
const STATUS_CFG = {
    pending: { label: 'Pendente', severity: 'warn' },
    paid: { label: 'Pago', severity: 'success' },
    overdue: { label: 'Vencido', severity: 'danger' },
    partial: { label: 'Parcial', severity: 'info' },
    cancelled: { label: 'Cancelado', severity: 'secondary' },
    refunded: { label: 'Estornado', severity: 'secondary', extraClass: 'tag-refunded' }
};

// ─── dialog: registrar pagamento ──────────────────────────────────────────────
const payDlgVisible = ref(false);
const payDlgRecord = ref(null);
const payDlgMethod = ref(null);
const payDlgLoading = ref(false);

function openPayDialog(record) {
    payDlgRecord.value = record;
    payDlgMethod.value = null;
    payDlgVisible.value = true;
}

async function confirmPayment() {
    if (!payDlgMethod.value || !payDlgRecord.value) return;
    payDlgLoading.value = true;
    try {
        const result = await markAsPaid(payDlgRecord.value.id, payDlgMethod.value);
        if (!result.ok) throw new Error(result.error);
        payDlgVisible.value = false;
        toast.add({ severity: 'success', summary: 'Pagamento registrado', detail: `${fmtBRL(payDlgRecord.value.final_amount)} via ${paymentLabel(payDlgMethod.value)}.`, life: 3000 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Não foi possível registrar o pagamento.', life: 4000 });
    } finally {
        payDlgLoading.value = false;
    }
}

// ─── cancelar cobrança ────────────────────────────────────────────────────────
function requestCancel(record) {
    confirm.require({
        message: `Deseja cancelar a cobrança de ${fmtBRL(record.final_amount)} para ${record.patients?.nome_completo ?? '—'}? Esta ação não pode ser desfeita.`,
        header: 'Cancelar cobrança',
        icon: 'pi pi-exclamation-triangle',
        rejectLabel: 'Não',
        acceptLabel: 'Sim, cancelar',
        acceptSeverity: 'danger',
        accept: async () => {
            const result = await cancelRecord(record.id);
            if (result.ok) {
                toast.add({ severity: 'info', summary: 'Cancelado', detail: 'Cobrança cancelada com sucesso.', life: 3000 });
            } else {
                toast.add({ severity: 'error', summary: 'Erro', detail: result.error || 'Não foi possível cancelar.', life: 4000 });
            }
        }
    });
}

// ─── dialog: lançamento manual ────────────────────────────────────────────────
const manualDlgVisible = ref(false);
const manualDlgLoading = ref(false);
const manualForm = ref({
    patient: null,
    amount: null,
    discount_amount: 0,
    due_date: null,
    payment_method: null,
    notes: ''
});

const manualFinalAmount = computed(() => {
    const a = manualForm.value.amount ?? 0;
    const d = manualForm.value.discount_amount ?? 0;
    return Math.max(0, a - d);
});

function openManualDlg() {
    manualForm.value = { patient: null, amount: null, discount_amount: 0, due_date: null, payment_method: null, notes: '' };
    manualDlgVisible.value = true;
}

async function saveManualRecord() {
    if (!manualForm.value.amount || !manualForm.value.due_date) {
        toast.add({ severity: 'warn', summary: 'Campos obrigatórios', detail: 'Preencha o valor e a data de vencimento.', life: 3500 });
        return;
    }
    manualDlgLoading.value = true;
    try {
        const due = manualForm.value.due_date instanceof Date ? manualForm.value.due_date.toISOString().slice(0, 10) : manualForm.value.due_date;

        const result = await createManualRecord({
            patient_id: manualForm.value.patient?.id ?? null,
            amount: manualForm.value.amount,
            discount_amount: manualForm.value.discount_amount ?? 0,
            due_date: due,
            payment_method: manualForm.value.payment_method ?? null,
            notes: manualForm.value.notes || null
        });
        if (!result.ok) throw new Error(result.error);
        manualDlgVisible.value = false;
        toast.add({ severity: 'success', summary: 'Lançamento criado', detail: 'Registro financeiro adicionado com sucesso.', life: 3000 });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message || 'Não foi possível salvar.', life: 4000 });
    } finally {
        manualDlgLoading.value = false;
    }
}

// ─── lifecycle ────────────────────────────────────────────────────────────────
onMounted(async () => {
    _observer = new IntersectionObserver(
        ([entry]) => {
            headerStuck.value = !entry.isIntersecting;
        },
        { threshold: 0, rootMargin: '-56px 0px 0px 0px' }
    );
    if (headerSentinelRef.value) _observer.observe(headerSentinelRef.value);
    await Promise.all([loadPatients(), applyFilters()]);
    mounted.value = true;
});

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

<template>
    <!-- Outer wrapper -->
    <div class="min-h-[calc(100vh-4.5rem)] bg-[var(--surface-ground,#f5f7fa)]">
        <!-- Sentinel -->
        <div ref="headerSentinelRef" class="h-px" />

        <!-- ══════════════════════════════════════
       Hero sticky
  ═══════════════════════════════════════ -->
        <div
            ref="headerEl"
            class="sticky mx-3 md:mx-4 z-20 overflow-hidden rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] transition-[border-radius] duration-200"
            :class="{ 'rounded-tl-none rounded-tr-none': headerStuck }"
            :style="{ top: 'var(--layout-sticky-top, 56px)' }"
        >
            <!-- Blobs decorativos -->
            <div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
                <div class="absolute w-64 h-64 -top-16 -right-8 rounded-full blur-[60px] bg-emerald-400/10" />
                <div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
            </div>

            <div class="relative z-1 px-3 pt-2.5 pb-2">
                <!-- Linha 1: brand + actions -->
                <div class="flex items-center gap-3">
                    <div class="flex items-center gap-2.5 flex-1 min-w-0">
                        <div class="cfg-subheader__icon grid place-items-center w-10 h-10 rounded-md shrink-0" style="background: color-mix(in srgb, #10b981 15%, transparent); color: #059669">
                            <i class="pi pi-wallet text-base" />
                        </div>
                        <div class="min-w-0">
                            <div class="text-[1.05rem] font-bold tracking-tight text-[var(--text-color)]">Financeiro</div>
                            <div class="text-[0.78rem] text-[var(--text-color-secondary)] hidden sm:block mt-0.5">Cobranças, recebimentos e lançamentos manuais</div>
                        </div>
                    </div>

                    <!-- Ações desktop -->
                    <div class="hidden sm:flex items-center gap-2 shrink-0">
                        <Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" v-tooltip.top="'Recarregar'" @click="applyFilters" />
                        <Button label="Lançamento manual" icon="pi pi-plus" class="rounded-full" @click="openManualDlg" />
                    </div>

                    <!-- Mobile -->
                    <div class="flex sm:hidden items-center gap-1 shrink-0">
                        <Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" @click="applyFilters" />
                        <Button icon="pi pi-plus" class="h-9 w-9 rounded-full" @click="openManualDlg" />
                    </div>
                </div>

                <!-- Linha 2: quick stats -->
                <div class="mt-2.5">
                    <template v-if="loading && !hasLoaded">
                        <div class="flex flex-wrap gap-2">
                            <div v-for="n in 3" :key="n" class="flex flex-col gap-1.5 px-4 py-2 rounded-md border border-[var(--surface-border)] flex-1 min-w-[80px]">
                                <Skeleton width="3rem" height="16px" />
                                <Skeleton width="4.5rem" height="10px" />
                            </div>
                        </div>
                    </template>

                    <template v-else>
                        <div class="flex flex-wrap gap-2">
                            <!-- Pendente -->
                            <div
                                class="flex flex-col gap-0.5 px-4 py-2 rounded-md border flex-1 min-w-[80px] cursor-pointer select-none transition-[border-color,box-shadow] duration-150"
                                :class="filterStatus === 'pending' ? 'border-amber-500/60 bg-amber-500/10 shadow-[0_0_0_3px_rgba(245,158,11,0.18)]' : 'border-amber-500/25 bg-amber-500/5 hover:border-amber-500/50'"
                                @click="filterStatus = filterStatus === 'pending' ? null : 'pending'"
                            >
                                <div class="text-[1.25rem] font-bold leading-none text-amber-500">{{ fmtBRL(summary.totalPending) }}</div>
                                <div class="flex items-center gap-1.5 text-[0.7rem] text-amber-600/80 font-semibold">
                                    <span class="h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse shrink-0" />
                                    Pendente
                                    <span class="ml-auto font-bold bg-amber-500/10 rounded-full px-1.5">{{ summary.countByStatus.pending ?? 0 }}</span>
                                </div>
                            </div>

                            <!-- Vencido -->
                            <div
                                class="flex flex-col gap-0.5 px-4 py-2 rounded-md border flex-1 min-w-[80px] cursor-pointer select-none transition-[border-color,box-shadow] duration-150"
                                :class="filterStatus === 'overdue' ? 'border-red-500/60 bg-red-500/10 shadow-[0_0_0_3px_rgba(239,68,68,0.18)]' : 'border-red-500/25 bg-red-500/5 hover:border-red-500/50'"
                                @click="filterStatus = filterStatus === 'overdue' ? null : 'overdue'"
                            >
                                <div class="text-[1.25rem] font-bold leading-none text-red-500">{{ fmtBRL(summary.totalOverdue) }}</div>
                                <div class="flex items-center gap-1.5 text-[0.7rem] text-red-600/80 font-semibold">
                                    <i class="pi pi-exclamation-circle text-xs" />
                                    Vencido
                                    <span class="ml-auto font-bold bg-red-500/10 rounded-full px-1.5">{{ summary.countByStatus.overdue ?? 0 }}</span>
                                </div>
                            </div>

                            <!-- Pago este mês -->
                            <div
                                class="flex flex-col gap-0.5 px-4 py-2 rounded-md border flex-1 min-w-[80px] cursor-pointer select-none transition-[border-color,box-shadow] duration-150"
                                :class="filterStatus === 'paid' ? 'border-emerald-500/60 bg-emerald-500/10 shadow-[0_0_0_3px_rgba(34,197,94,0.18)]' : 'border-emerald-500/25 bg-emerald-500/5 hover:border-emerald-500/50'"
                                @click="filterStatus = filterStatus === 'paid' ? null : 'paid'"
                            >
                                <div class="text-[1.25rem] font-bold leading-none text-emerald-600">{{ fmtBRL(summary.totalPaidThisMonth) }}</div>
                                <div class="flex items-center gap-1.5 text-[0.7rem] text-emerald-700/80 font-semibold">
                                    <i class="pi pi-check-circle text-xs" />
                                    Pago (mês)
                                    <span class="ml-auto font-bold bg-emerald-500/10 rounded-full px-1.5">{{ summary.countByStatus.paid ?? 0 }}</span>
                                </div>
                            </div>
                        </div>
                    </template>
                </div>
            </div>
        </div>

        <!-- ══════════════════════════════════════
       Conteúdo principal
  ═══════════════════════════════════════ -->
        <div class="px-3 md:px-4 pt-3 pb-4 flex flex-col gap-3.5">
            <!-- ══════════════════════════════════════
       Filtros
  ═══════════════════════════════════════ -->
            <section class="dash-card rounded-md">
                <div class="dash-card__head gap-2.5 p-2.5">
                    <div class="grid place-items-center w-10 h-10 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
                        <i class="pi pi-filter text-lg" />
                    </div>
                    <div class="flex-1 min-w-0">
                        <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Filtros</div>
                        <div class="dash-card__sub">Refine por status, tipo, paciente ou período</div>
                    </div>
                    <Button v-if="hasActiveFilters" label="Limpar" icon="pi pi-filter-slash" severity="danger" outlined size="small" class="rounded-full ml-auto shrink-0" @click="clearFilters" />
                </div>
                <div class="px-4 py-3">
                    <div class="flex flex-col sm:flex-row sm:flex-wrap items-start sm:items-end gap-3">
                        <!-- Status -->
                        <div class="w-full sm:w-40">
                            <FloatLabel variant="on">
                                <Select id="fin-filter-status" v-model="filterStatus" :options="STATUS_OPTIONS" optionLabel="label" optionValue="value" class="w-full" />
                                <label for="fin-filter-status">Status</label>
                            </FloatLabel>
                        </div>

                        <!-- Tipo -->
                        <div class="w-full sm:w-36">
                            <FloatLabel variant="on">
                                <Select id="fin-filter-type" v-model="filterType" :options="TYPE_OPTIONS" optionLabel="label" optionValue="value" class="w-full" />
                                <label for="fin-filter-type">Tipo</label>
                            </FloatLabel>
                        </div>

                        <!-- Paciente -->
                        <div class="w-full sm:w-56">
                            <FloatLabel variant="on">
                                <Select id="fin-filter-patient" v-model="filterPatient" :options="patients" optionLabel="nome_completo" filter :filterFields="['nome_completo']" showClear class="w-full">
                                    <template #option="{ option }">
                                        <div class="flex items-center gap-2">
                                            <span class="h-2 w-2 rounded-full shrink-0" :style="option.identification_color ? { background: option.identification_color } : { background: 'var(--surface-border)' }" />
                                            <span>{{ option.nome_completo }}</span>
                                        </div>
                                    </template>
                                </Select>
                                <label for="fin-filter-patient">Paciente</label>
                            </FloatLabel>
                        </div>

                        <!-- Período (range de vencimento) -->
                        <div class="w-full sm:w-64">
                            <FloatLabel variant="on">
                                <DatePicker id="fin-filter-date" v-model="filterDateRange" selectionMode="range" showIcon iconDisplay="input" dateFormat="dd/mm/yy" :manualInput="false" class="w-full" />
                                <label for="fin-filter-date">Período de vencimento</label>
                            </FloatLabel>
                        </div>
                    </div>
                </div>
            </section>

            <!-- ══════════════════════════════════════
       Erro de carregamento
  ═══════════════════════════════════════ -->
            <div v-if="error" class="rounded-md border border-red-500/30 bg-red-500/5 px-4 py-3 flex items-center gap-3 text-red-600">
                <i class="pi pi-exclamation-triangle shrink-0" />
                <span class="text-[1rem]">{{ error }}</span>
                <Button icon="pi pi-refresh" severity="danger" text size="small" class="ml-auto" @click="applyFilters" />
            </div>

            <!-- ══════════════════════════════════════
       Cards mobile (< md)
  ═══════════════════════════════════════ -->
            <section class="md:hidden">
                <!-- Skeleton mobile -->
                <template v-if="loading && !hasLoaded">
                    <div v-for="n in 5" :key="n" class="mb-2 rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 flex flex-col gap-2">
                        <div class="flex items-center gap-2">
                            <Skeleton shape="circle" size="2rem" />
                            <Skeleton height="1rem" class="flex-1" />
                            <Skeleton height="1.5rem" width="4.5rem" />
                        </div>
                        <div class="flex gap-2">
                            <Skeleton height="0.9rem" class="flex-1" />
                            <Skeleton height="0.9rem" width="5rem" />
                        </div>
                        <div class="flex gap-1.5 pt-1">
                            <Skeleton height="2rem" class="flex-1 rounded-full" />
                            <Skeleton height="2rem" class="flex-1 rounded-full" />
                        </div>
                    </div>
                </template>

                <!-- Empty mobile -->
                <div v-else-if="hasLoaded && !records.length" class="rounded-md border border-dashed border-[var(--surface-border)] bg-[var(--surface-ground)] p-8 flex flex-col items-center gap-3 text-center text-[var(--text-color-secondary)]">
                    <i class="pi pi-wallet text-3xl opacity-20" />
                    <div class="font-semibold">Nenhum registro encontrado</div>
                    <div class="text-sm opacity-60">Tente limpar os filtros ou adicione um lançamento</div>
                    <div class="flex gap-2 mt-1 flex-wrap justify-center">
                        <Button v-if="hasActiveFilters" severity="secondary" outlined icon="pi pi-filter-slash" label="Limpar filtros" size="small" class="rounded-full" @click="clearFilters" />
                        <Button icon="pi pi-plus" label="Lançamento manual" size="small" class="rounded-full" @click="openManualDlg" />
                    </div>
                </div>

                <!-- Lista mobile -->
                <template v-else>
                    <div v-for="rec in records" :key="rec.id" class="mb-2 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] p-3 flex flex-col gap-2.5" :class="rec.status === 'overdue' ? 'border-red-400/40' : ''">
                        <!-- Linha 1: paciente + valor + status -->
                        <div class="flex items-start gap-2.5">
                            <div
                                class="h-8 w-8 rounded-full shrink-0 grid place-items-center text-white text-xs font-bold mt-0.5"
                                :style="rec.patients?.identification_color ? { background: rec.patients.identification_color } : { background: 'var(--primary-color, #6366f1)' }"
                            >
                                {{ rec.patients?.nome_completo?.[0]?.toUpperCase() ?? '?' }}
                            </div>
                            <div class="flex-1 min-w-0">
                                <div class="font-semibold text-sm text-[var(--text-color)] leading-tight truncate">
                                    {{ rec.patients?.nome_completo ?? 'Sem paciente' }}
                                </div>
                                <div class="text-[0.75rem] text-[var(--text-color-secondary)] mt-0.5">
                                    {{ rec.agenda_eventos ? fmtDateTime(rec.agenda_eventos.inicio_em) : 'Lançamento manual' }}
                                </div>
                            </div>
                            <div class="flex flex-col items-end gap-1 shrink-0">
                                <span class="font-bold text-[var(--text-color)]">{{ fmtBRL(rec.final_amount) }}</span>
                                <Tag :value="STATUS_CFG[rec.status]?.label ?? rec.status" :severity="STATUS_CFG[rec.status]?.severity" class="text-xs" />
                            </div>
                        </div>

                        <!-- Linha 2: vencimento + método -->
                        <div class="flex items-center gap-3 text-[0.75rem] text-[var(--text-color-secondary)]">
                            <div class="flex items-center gap-1" :class="rec.status === 'overdue' || (rec.status === 'pending' && isOverdueDate(rec.due_date)) ? 'text-red-500 font-semibold' : ''">
                                <i class="pi pi-calendar text-xs" />
                                Vence {{ fmtDate(rec.due_date) }}
                            </div>
                            <div v-if="rec.paid_at" class="flex items-center gap-1 text-emerald-600">
                                <i class="pi pi-check text-xs" />
                                {{ paymentLabel(rec.payment_method) }}
                            </div>
                        </div>

                        <!-- Ações mobile -->
                        <div v-if="rec.status === 'pending' || rec.status === 'overdue'" class="flex gap-1.5 pt-1 border-t border-[var(--surface-border)]">
                            <Button label="Receber" icon="pi pi-check" size="small" class="rounded-full flex-1" @click="openPayDialog(rec)" />
                            <Button icon="pi pi-times" size="small" severity="danger" outlined class="rounded-full h-8 w-8" v-tooltip.top="'Cancelar cobrança'" @click="requestCancel(rec)" />
                        </div>
                        <div v-else-if="rec.status === 'paid'" class="flex items-center gap-1.5 text-[0.75rem] text-emerald-600 pt-1 border-t border-[var(--surface-border)]">
                            <i class="pi pi-check-circle" />
                            Pago em {{ fmtDate(rec.paid_at) }} via {{ paymentLabel(rec.payment_method) }}
                        </div>
                    </div>
                </template>
            </section>

            <!-- ══════════════════════════════════════
       DataTable (desktop ≥ md)
  ═══════════════════════════════════════ -->
            <section class="hidden md:block dash-card rounded-md shadow-[0_0_0_3px_color-mix(in_srgb,var(--primary-color)_7%,transparent)]">
                <!-- Header -->
                <div class="dash-card__head gap-2.5 p-2.5">
                    <div class="grid place-items-center w-10 h-10 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
                        <i class="pi pi-table text-lg" />
                    </div>
                    <div class="flex-1">
                        <div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Registros</div>
                        <div class="dash-card__sub">Lista completa de cobranças e lançamentos</div>
                    </div>
                    <span
                        class="dash-card__badge"
                        style="background: color-mix(in srgb, var(--primary-color, #6366f1) 10%, transparent); color: var(--primary-color, #6366f1); border: 1px solid color-mix(in srgb, var(--primary-color, #6366f1) 30%, transparent)"
                    >
                        {{ records.length }}
                    </span>
                </div>

                <DataTable
                    :value="records"
                    dataKey="id"
                    :loading="loading"
                    lazy
                    :paginator="true"
                    :rows="pageRows"
                    :first="pageFirst"
                    :totalRecords="totalRecords"
                    :rowsPerPageOptions="[10, 20, 50]"
                    paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown CurrentPageReport"
                    currentPageReportTemplate="{first}–{last} de {totalRecords}"
                    scrollable
                    scrollHeight="520px"
                    class="p-datatable-sm"
                    :rowClass="(r) => (r.status === 'overdue' ? 'bg-red-500/[0.03]' : '')"
                    emptyMessage="Nenhum registro encontrado para os filtros selecionados."
                    @page="onPageChange"
                >
                    <!-- Paciente -->
                    <Column header="Paciente" style="min-width: 13rem">
                        <template #body="{ data }">
                            <div class="flex items-center gap-2">
                                <div
                                    class="h-6 w-6 rounded-full shrink-0 grid place-items-center text-white text-[0.6rem] font-bold"
                                    :style="data.patients?.identification_color ? { background: data.patients.identification_color } : { background: 'var(--primary-color, #6366f1)' }"
                                >
                                    {{ data.patients?.nome_completo?.[0]?.toUpperCase() ?? '?' }}
                                </div>
                                <span class="text-sm font-medium truncate max-w-[10rem]">{{ data.patients?.nome_completo ?? '—' }}</span>
                            </div>
                        </template>
                    </Column>

                    <!-- Sessão -->
                    <Column header="Sessão" style="min-width: 10rem">
                        <template #body="{ data }">
                            <span v-if="data.agenda_eventos" class="text-sm">
                                {{ fmtDateTime(data.agenda_eventos.inicio_em) }}
                            </span>
                            <span v-else class="inline-flex items-center gap-1 text-[0.75rem] text-[var(--text-color-secondary)] bg-[var(--surface-ground)] px-2 py-0.5 rounded-full border border-[var(--surface-border)]">
                                <i class="pi pi-pencil text-xs" />
                                Manual
                            </span>
                        </template>
                    </Column>

                    <!-- Tipo -->
                    <Column header="Tipo" style="min-width: 7rem">
                        <template #body="{ data }">
                            <Tag :value="data.type === 'receita' ? 'Receita' : 'Despesa'" :severity="data.type === 'receita' ? 'success' : 'danger'" class="text-xs" />
                        </template>
                    </Column>

                    <!-- Valor -->
                    <Column header="Valor" style="min-width: 7rem" sortable field="final_amount">
                        <template #body="{ data }">
                            <div class="flex flex-col">
                                <span class="font-semibold text-sm">{{ fmtBRL(data.final_amount) }}</span>
                                <span v-if="data.discount_amount > 0" class="text-[0.7rem] text-[var(--text-color-secondary)] line-through">
                                    {{ fmtBRL(data.amount) }}
                                </span>
                            </div>
                        </template>
                    </Column>

                    <!-- Vencimento -->
                    <Column header="Vencimento" style="min-width: 8rem" sortable field="due_date">
                        <template #body="{ data }">
                            <span class="text-sm" :class="data.status === 'overdue' || (data.status === 'pending' && isOverdueDate(data.due_date)) ? 'text-red-500 font-semibold' : 'text-[var(--text-color)]'">
                                <i v-if="data.status === 'overdue'" class="pi pi-exclamation-circle text-xs mr-1" />
                                {{ fmtDate(data.due_date) }}
                            </span>
                        </template>
                    </Column>

                    <!-- Status -->
                    <Column header="Status" style="min-width: 8rem">
                        <template #body="{ data }">
                            <Tag :value="STATUS_CFG[data.status]?.label ?? data.status" :severity="STATUS_CFG[data.status]?.severity ?? 'secondary'" :class="['text-xs', STATUS_CFG[data.status]?.extraClass ?? '']" />
                        </template>
                    </Column>

                    <!-- Ações -->
                    <Column header="Ações" style="min-width: 11rem; width: 11rem">
                        <template #body="{ data }">
                            <!-- Pendente / Vencido -->
                            <div v-if="data.status === 'pending' || data.status === 'overdue'" class="flex items-center gap-1">
                                <Button label="Receber" icon="pi pi-check" size="small" class="rounded-full" @click="openPayDialog(data)" />
                                <Button icon="pi pi-times" size="small" severity="danger" outlined class="rounded-full h-7 w-7" v-tooltip.top="'Cancelar cobrança'" @click="requestCancel(data)" />
                            </div>

                            <!-- Pago -->
                            <div v-else-if="data.status === 'paid'" class="flex flex-col gap-0.5">
                                <div class="flex items-center gap-1 text-[0.75rem] text-emerald-600 font-medium">
                                    <i class="pi pi-check-circle text-xs" />
                                    {{ paymentLabel(data.payment_method) }}
                                </div>
                                <div class="text-[0.7rem] text-[var(--text-color-secondary)]">{{ fmtDate(data.paid_at) }}</div>
                            </div>

                            <!-- Cancelado -->
                            <span v-else class="text-[0.75rem] text-[var(--text-color-secondary)] opacity-50 italic">—</span>
                        </template>
                    </Column>
                </DataTable>
            </section>

            <!-- LoadedPhraseBlock -->
            <div>
                <LoadedPhraseBlock v-if="hasLoaded" />
            </div>
        </div>
        <!-- /conteúdo principal -->
    </div>
    <!-- /outer wrapper -->

    <!-- ══════════════════════════════════════
       Dialog: Registrar Pagamento
  ═══════════════════════════════════════ -->
    <Dialog v-model:visible="payDlgVisible" modal :draggable="false" pt:mask:class="backdrop-blur-xs" header="Registrar pagamento" class="w-[94vw] max-w-md">
        <div v-if="payDlgRecord" class="flex flex-col gap-5 pt-1">
            <!-- Resumo da cobrança -->
            <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] px-4 py-3 flex items-center justify-between gap-3">
                <div class="min-w-0">
                    <div class="font-semibold text-sm text-[var(--text-color)] truncate">{{ payDlgRecord.patients?.nome_completo ?? '—' }}</div>
                    <div class="text-[0.75rem] text-[var(--text-color-secondary)] mt-0.5">Vencimento: {{ fmtDate(payDlgRecord.due_date) }}</div>
                </div>
                <div class="text-right shrink-0">
                    <div class="text-lg font-bold text-[var(--text-color)]">{{ fmtBRL(payDlgRecord.final_amount) }}</div>
                    <div v-if="payDlgRecord.discount_amount > 0" class="text-[0.7rem] text-[var(--text-color-secondary)] line-through">
                        {{ fmtBRL(payDlgRecord.amount) }}
                    </div>
                </div>
            </div>

            <!-- Método de pagamento -->
            <div>
                <div class="text-sm font-semibold text-[var(--text-color)] mb-2">Método de pagamento</div>
                <div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
                    <button
                        v-for="opt in PAYMENT_METHOD_OPTIONS"
                        :key="opt.value"
                        type="button"
                        class="flex flex-col items-center gap-1.5 px-3 py-2.5 rounded-md border text-sm font-medium transition-all duration-150 cursor-pointer select-none"
                        :class="
                            payDlgMethod === opt.value
                                ? 'border-[var(--primary-color,#6366f1)] bg-[var(--primary-color,#6366f1)]/10 text-[var(--primary-color,#6366f1)]'
                                : 'border-[var(--surface-border)] bg-[var(--surface-ground)] text-[var(--text-color-secondary)] hover:border-[var(--primary-color,#6366f1)]/40'
                        "
                        @click="payDlgMethod = opt.value"
                    >
                        <i
                            class="text-base"
                            :class="{
                                'pi pi-bolt': opt.value === 'pix',
                                'pi pi-building': opt.value === 'deposito',
                                'pi pi-money-bill': opt.value === 'dinheiro',
                                'pi pi-credit-card': opt.value === 'cartao',
                                'pi pi-id-card': opt.value === 'convenio'
                            }"
                        />
                        {{ opt.label }}
                    </button>
                </div>
            </div>
        </div>

        <template #footer>
            <Button label="Cancelar" severity="secondary" outlined class="rounded-full" :disabled="payDlgLoading" @click="payDlgVisible = false" />
            <Button label="Confirmar pagamento" icon="pi pi-check" class="rounded-full" :loading="payDlgLoading" :disabled="!payDlgMethod" @click="confirmPayment" />
        </template>
    </Dialog>

    <!-- ══════════════════════════════════════
       Dialog: Lançamento Manual
  ═══════════════════════════════════════ -->
    <Dialog v-model:visible="manualDlgVisible" modal :draggable="false" pt:mask:class="backdrop-blur-xs" header="Lançamento manual" class="w-[94vw] max-w-lg">
        <div class="flex flex-col gap-4 pt-1">
            <!-- Paciente -->
            <div>
                <label class="text-sm font-semibold text-[var(--text-color)] block mb-1.5">Paciente <span class="text-[var(--text-color-secondary)] font-normal">(opcional)</span></label>
                <Select v-model="manualForm.patient" :options="patients" optionLabel="nome_completo" filter :filterFields="['nome_completo']" showClear placeholder="Selecionar paciente..." class="w-full">
                    <template #option="{ option }">
                        <div class="flex items-center gap-2">
                            <span class="h-2 w-2 rounded-full shrink-0" :style="option.identification_color ? { background: option.identification_color } : { background: 'var(--surface-border)' }" />
                            <span>{{ option.nome_completo }}</span>
                        </div>
                    </template>
                </Select>
            </div>

            <!-- Valor + Desconto -->
            <div class="grid grid-cols-2 gap-3">
                <div>
                    <label class="text-sm font-semibold text-[var(--text-color)] block mb-1.5">Valor *</label>
                    <InputNumber v-model="manualForm.amount" mode="currency" currency="BRL" locale="pt-BR" placeholder="R$ 0,00" class="w-full" :min="0" />
                </div>
                <div>
                    <label class="text-sm font-semibold text-[var(--text-color)] block mb-1.5">Desconto</label>
                    <InputNumber v-model="manualForm.discount_amount" mode="currency" currency="BRL" locale="pt-BR" placeholder="R$ 0,00" class="w-full" :min="0" />
                </div>
            </div>

            <!-- Valor final (read-only) -->
            <div class="flex items-center justify-between px-4 py-2.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)]">
                <span class="text-sm text-[var(--text-color-secondary)]">Valor final a cobrar</span>
                <span class="font-bold text-[var(--text-color)]">{{ fmtBRL(manualFinalAmount) }}</span>
            </div>

            <!-- Data de vencimento -->
            <div>
                <label class="text-sm font-semibold text-[var(--text-color)] block mb-1.5">Data de vencimento *</label>
                <DatePicker v-model="manualForm.due_date" showIcon iconDisplay="input" dateFormat="dd/mm/yy" :manualInput="false" class="w-full" />
            </div>

            <!-- Método de pagamento (opcional) -->
            <div>
                <label class="text-sm font-semibold text-[var(--text-color)] block mb-1.5">Método de pagamento <span class="text-[var(--text-color-secondary)] font-normal">(opcional)</span></label>
                <Select v-model="manualForm.payment_method" :options="PAYMENT_METHOD_OPTIONS" optionLabel="label" optionValue="value" showClear placeholder="Selecionar método..." class="w-full" />
            </div>

            <!-- Observações -->
            <div>
                <label class="text-sm font-semibold text-[var(--text-color)] block mb-1.5">Observações</label>
                <Textarea v-model="manualForm.notes" placeholder="Anotações internas sobre este lançamento..." rows="3" class="w-full resize-none" />
            </div>
        </div>

        <template #footer>
            <Button label="Cancelar" severity="secondary" outlined class="rounded-full" :disabled="manualDlgLoading" @click="manualDlgVisible = false" />
            <Button label="Salvar lançamento" icon="pi pi-check" class="rounded-full" :loading="manualDlgLoading" @click="saveManualRecord" />
        </template>
    </Dialog>

    <!-- ConfirmDialog global -->
    <ConfirmDialog />
</template>

<style scoped>
/* ── tag: estornado (roxo — sem severity nativo) ── */
:deep(.tag-refunded) {
    background: #a855f7 !important;
    color: #fff !important;
}
</style>
