<script setup>
/*
 * MelissaCadastrosRecebidos — Cadastros recebidos (intake requests externos).
 * Segue blueprint melissa-page-blueprint.md.
 *
 * Layout 2-col:
 *   - COL 1 — Aside (~280px): stats por status (Novo/Convertido/Rejeitado)
 *            + filtros (status pill toggle) + busca
 *   - COL 2 — Lista de cards de cadastro (avatar + nome + telefone/email +
 *            status badge + tempo)
 *
 * Click num card → dialog com detalhes + ações (Rejeitar / Converter em paciente).
 * Reaproveita a lógica de patient_intake_requests da página antiga.
 */
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 { useTenantStore } from '@/stores/tenantStore';
import { brToISO, isoToBR } from '@/utils/dateBR';
// Dialog/Textarea/Button auto-imported via PrimeVueResolver

const emit = defineEmits(['close']);
const toast = useToast();
const confirm = useConfirm();
const tenantStore = useTenantStore();

// ── Breakpoints + drawer ───────────────────────────────────
const drawerOpen = ref(false);
const isMobile = ref(false);
let _mqMobile = null;
function _onMqMobileChange(e) {
    isMobile.value = e.matches;
    if (!e.matches) drawerOpen.value = false;
}
function toggleDrawer() { drawerOpen.value = !drawerOpen.value; }
function fecharDrawer() { drawerOpen.value = false; }

// ── Estado ─────────────────────────────────────────────────
const loading = ref(false);
const converting = ref(false);
const rows = ref([]);
const busca = ref('');
const statusFilter = ref('');

const carregandoInicial = computed(
    () => loading.value && rows.value.length === 0
);

// ── Helpers de campos (espelhados da CadastrosRecebidosPage) ──
function pickField(obj, keys) {
    for (const k of keys) {
        const v = obj?.[k];
        if (v !== undefined && v !== null && String(v).trim() !== '') return v;
    }
    return null;
}
const fNome = (i) => pickField(i, ['nome_completo', 'name']);
const fEmail = (i) => pickField(i, ['email_principal', 'email']);
const fEmailAlt = (i) => pickField(i, ['email_alternativo', 'email_alt']);
const fTel = (i) => pickField(i, ['telefone', 'phone']);
const fTelAlt = (i) => pickField(i, ['telefone_alternativo', 'phone_alt']);
const fNasc = (i) => pickField(i, ['data_nascimento', 'birth_date']);
const fGenero = (i) => pickField(i, ['genero', 'gender']);
const fProf = (i) => pickField(i, ['profissao', 'profession']);
const fCep = (i) => pickField(i, ['cep']);
const fEndereco = (i) => pickField(i, ['endereco', 'address_street']);
const fNumero = (i) => pickField(i, ['numero', 'address_number']);
const fBairro = (i) => pickField(i, ['bairro', 'address_neighborhood']);
const fCidade = (i) => pickField(i, ['cidade', 'address_city']);
const fEstado = (i) => pickField(i, ['estado', 'address_state']);
const fEstadoCivil = (i) => pickField(i, ['estado_civil', 'marital_status']);
const fNaturalidade = (i) => pickField(i, ['naturalidade', 'place_of_birth']);
const fEscolaridade = (i) => pickField(i, ['escolaridade', 'education_level']);
const fOndeConheceu = (i) => pickField(i, ['onde_nos_conheceu', 'lead_source']);
const fEncaminhado = (i) => pickField(i, ['encaminhado_por', 'referred_by']);
const fObs = (i) => pickField(i, ['observacoes', 'notes_short']);
const fComplemento = (i) => pickField(i, ['complemento', 'address_complement']);
const fPais = (i) => pickField(i, ['pais', 'country']) || 'Brasil';
const fEmailAlt2 = (i) => pickField(i, ['email_alternativo', 'email_alt']);

// ── Formatters ─────────────────────────────────────────────
function dash(v) {
    const s = String(v ?? '').trim();
    return s ? s : '—';
}
function onlyDigits(v) { return String(v ?? '').replace(/\D/g, ''); }
function fmtPhoneBR(v) {
    const d = onlyDigits(v);
    if (!d) return '—';
    if (d.length === 11) return `(${d.slice(0,2)}) ${d.slice(2,7)}-${d.slice(7,11)}`;
    if (d.length === 10) return `(${d.slice(0,2)}) ${d.slice(2,6)}-${d.slice(6,10)}`;
    return d;
}
function fmtCPF(v) {
    const d = onlyDigits(v);
    if (!d || d.length !== 11) return d || '—';
    return `${d.slice(0,3)}.${d.slice(3,6)}.${d.slice(6,9)}-${d.slice(9,11)}`;
}
function fmtBirth(v) {
    if (!v) return '—';
    const s = String(v).trim();
    if (/^\d{2}-\d{2}-\d{4}$/.test(s)) return s;
    if (/^\d{4}-\d{2}-\d{2}/.test(s)) return isoToBR(s.slice(0, 10)) || s;
    return s;
}
function normalizeBirthToISO(v) {
    if (!v) return null;
    const s = String(v).trim();
    if (!s) return null;
    if (/^\d{2}-\d{2}-\d{4}$/.test(s)) return brToISO(s);
    if (/^\d{4}-\d{2}-\d{2}/.test(s)) return s.slice(0, 10);
    const d = new Date(s);
    if (Number.isNaN(d.getTime())) return null;
    return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
}
function fmtRelative(iso) {
    if (!iso) return '—';
    const d = new Date(iso);
    const now = new Date();
    const diff = Math.floor((now - d) / 1000);
    if (diff < 60) return 'agora';
    if (diff < 3600) return `${Math.floor(diff / 60)}m`;
    if (diff < 86400) return `${Math.floor(diff / 3600)}h`;
    if (diff < 604800) return `${Math.floor(diff / 86400)}d`;
    return d.toLocaleDateString('pt-BR');
}
function pacienteIniciais(nome) {
    if (!nome) return '?';
    const partes = String(nome).trim().split(/\s+/);
    if (partes.length === 1) return partes[0][0]?.toUpperCase() || '?';
    return (partes[0][0] + partes[partes.length - 1][0]).toUpperCase();
}

// ── Avatar URL ─────────────────────────────────────────────
const AVATAR_BUCKET = 'avatars';
function looksLikeUrl(s) { return /^https?:\/\//i.test(String(s || '')); }
function firstNonEmpty(...vals) {
    for (const v of vals) {
        const s = String(v ?? '').trim();
        if (s) return s;
    }
    return '';
}
function avatarUrl(row) {
    const p = row?.payload || row?.data || row?.form || null;
    const direct = firstNonEmpty(row?.avatar_url, row?.foto_url, row?.photo_url, p?.avatar_url, p?.foto_url, p?.photo_url);
    if (direct && looksLikeUrl(direct)) return direct;
    const path = firstNonEmpty(row?.avatar_path, row?.photo_path, p?.avatar_path, p?.photo_path, direct);
    if (!path) return null;
    if (looksLikeUrl(path)) return path;
    const { data } = supabase.storage.from(AVATAR_BUCKET).getPublicUrl(path);
    return data?.publicUrl || null;
}

// ── Status helpers ─────────────────────────────────────────
function statusLabel(s) {
    if (s === 'new') return 'Novo';
    if (s === 'converted') return 'Convertido';
    if (s === 'rejected') return 'Rejeitado';
    return s || '—';
}
function statusClass(s) {
    if (s === 'new') return 'is-new';
    if (s === 'converted') return 'is-done';
    if (s === 'rejected') return 'is-rejected';
    return '';
}

// ── Stats ──────────────────────────────────────────────────
const stats = computed(() => {
    const all = rows.value;
    const n = all.filter((r) => r.status === 'new').length;
    const c = all.filter((r) => r.status === 'converted').length;
    const r = all.filter((r) => r.status === 'rejected').length;
    return [
        { key: 'total', label: 'Total', value: all.length, cls: 'neutral' },
        { key: 'new', label: 'Novos', value: n, cls: n > 0 ? 'warn' : 'neutral' },
        { key: 'converted', label: 'Convertidos', value: c, cls: 'ok' },
        { key: 'rejected', label: 'Rejeitados', value: r, cls: 'neutral' }
    ];
});

const STATUS_FILTER_OPTIONS = [
    { key: 'new', label: 'Novos', icon: 'pi pi-bell' },
    { key: 'converted', label: 'Convertidos', icon: 'pi pi-check' },
    { key: 'rejected', label: 'Rejeitados', icon: 'pi pi-times' }
];

function toggleStatusFilter(s) {
    statusFilter.value = statusFilter.value === s ? '' : s;
}

// ── Filtragem ──────────────────────────────────────────────
const filtered = computed(() => {
    const term = String(busca.value || '').trim().toLowerCase();
    let list = rows.value;
    if (statusFilter.value) list = list.filter((r) => r.status === statusFilter.value);
    if (!term) return list;
    return list.filter((r) => {
        const nome = String(fNome(r) || '').toLowerCase();
        const email = String(fEmail(r) || '').toLowerCase();
        const tel = String(fTel(r) || '').toLowerCase();
        return nome.includes(term) || email.includes(term) || tel.includes(term);
    });
});

// ── Paginação client-side (default 10 por página) ──────────
// `fetchIntakes` traz a lista completa de patient_intake_requests do
// tenant — paginamos no client. Volume típico é baixo (cadastros
// recebidos via formulário externo), mas o Paginator + dropdown dão
// controle pro usuário caso a fila esteja grande.
const PAGE_SIZE_OPTIONS = [10, 20, 50, 100];
const pageMCR = ref(1);
const rowsMCR = ref(10);
const filteredPaginated = computed(() => {
    const start = (pageMCR.value - 1) * rowsMCR.value;
    return filtered.value.slice(start, start + rowsMCR.value);
});
function onPageMCRChange(event) {
    pageMCR.value = event.page + 1;
    rowsMCR.value = event.rows;
}
// Reset pra página 1 quando busca/status mudam.
watch([busca, statusFilter], () => { pageMCR.value = 1; });
// Clamp se a lista encolher (ex.: depois de converter/rejeitar e refetch).
watch(() => filtered.value.length, (len) => {
    const maxPag = Math.max(1, Math.ceil(len / rowsMCR.value));
    if (pageMCR.value > maxPag) pageMCR.value = maxPag;
});

// ── Fetch ──────────────────────────────────────────────────
async function fetchIntakes() {
    loading.value = true;
    try {
        const { data, error } = await supabase
            .from('patient_intake_requests').select('*')
            .order('created_at', { ascending: false });
        if (error) throw error;
        const weight = (s) => (s === 'new' ? 0 : s === 'converted' ? 1 : s === 'rejected' ? 2 : 9);
        rows.value = (data || []).slice().sort((a, b) => {
            const wa = weight(a.status), wb = weight(b.status);
            if (wa !== wb) return wa - wb;
            return new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime();
        });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao carregar', detail: e?.message || String(e), life: 3500 });
    } finally {
        loading.value = false;
    }
}

// ── Dialog detalhes ────────────────────────────────────────
const dlg = ref({ open: false, item: null, saving: false, reject_note: '' });

function openDetails(row) {
    dlg.value.open = true;
    dlg.value.item = row;
    dlg.value.reject_note = row?.rejected_reason || '';
}
function closeDlg() {
    dlg.value.open = false;
    dlg.value.saving = false;
    dlg.value.item = null;
    dlg.value.reject_note = '';
}

const dlgAvatarUrl = computed(() => dlg.value.item ? avatarUrl(dlg.value.item) : null);

const dlgSections = computed(() => {
    const i = dlg.value.item;
    if (!i) return [];
    const sec = (title, rs) => ({ title, rows: rs.filter((r) => r.value && r.value !== '—') });
    return [
        sec('Identificação', [
            { label: 'Email', value: dash(fEmail(i)) },
            { label: 'Email alt.', value: dash(fEmailAlt(i)) },
            { label: 'Telefone', value: fmtPhoneBR(fTel(i)) },
            { label: 'Tel. alt.', value: fmtPhoneBR(fTelAlt(i)) },
            { label: 'Nascimento', value: fmtBirth(fNasc(i)) },
            { label: 'Gênero', value: dash(fGenero(i)) },
            { label: 'Estado civil', value: dash(fEstadoCivil(i)) }
        ]),
        sec('Documentos', [
            { label: 'CPF', value: fmtCPF(i.cpf) },
            { label: 'RG', value: dash(i.rg) }
        ]),
        sec('Endereço', [
            { label: 'CEP', value: dash(fCep(i)) },
            { label: 'Endereço', value: [fEndereco(i), fNumero(i)].filter(Boolean).join(', ') || '—' },
            { label: 'Complemento', value: dash(fComplemento(i)) },
            { label: 'Bairro', value: dash(fBairro(i)) },
            { label: 'Cidade/UF', value: [fCidade(i), fEstado(i)].filter(Boolean).join('/') || '—' },
            { label: 'País', value: fPais(i) }
        ]),
        sec('Profissional', [
            { label: 'Profissão', value: dash(fProf(i)) },
            { label: 'Escolaridade', value: dash(fEscolaridade(i)) },
            { label: 'Naturalidade', value: dash(fNaturalidade(i)) },
            { label: 'Onde conheceu', value: dash(fOndeConheceu(i)) },
            { label: 'Encaminhado por', value: dash(fEncaminhado(i)) }
        ]),
        sec('Observações', [
            { label: 'Obs.', value: dash(fObs(i)) },
            { label: 'Notas internas', value: dash(i.notas_internas || i.notes) }
        ])
    ].filter((s) => s.rows.length > 0);
});

// ── Rejeitar ───────────────────────────────────────────────
async function markRejected() {
    const item = dlg.value.item;
    if (!item) return;
    confirm.require({
        message: 'Marcar este cadastro como rejeitado?',
        header: 'Confirmar rejeição',
        icon: 'pi pi-exclamation-triangle',
        acceptLabel: 'Rejeitar',
        rejectLabel: 'Cancelar',
        acceptSeverity: 'danger',
        accept: async () => {
            dlg.value.saving = true;
            try {
                const reason = String(dlg.value.reject_note || '').trim() || null;
                const { error } = await supabase.from('patient_intake_requests')
                    .update({ status: 'rejected', rejected_reason: reason, updated_at: new Date().toISOString() })
                    .eq('id', item.id);
                if (error) throw error;
                toast.add({ severity: 'success', summary: 'Rejeitado', life: 2200 });
                await fetchIntakes();
                const updated = rows.value.find((r) => r.id === item.id);
                if (updated) openDetails(updated); else closeDlg();
            } catch (e) {
                toast.add({ severity: 'error', summary: 'Erro', detail: e?.message, life: 4500 });
            } finally {
                dlg.value.saving = false;
            }
        }
    });
}

// ── Converter ──────────────────────────────────────────────
async function getResponsibleMemberId(tenantId, userId) {
    const { data, error } = await supabase.from('tenant_members')
        .select('id').eq('tenant_id', tenantId).eq('user_id', userId)
        .eq('status', 'active').maybeSingle();
    if (error) throw error;
    if (!data?.id) throw new Error('Membro responsável não encontrado.');
    return data.id;
}

async function convertToPatient() {
    const item = dlg.value?.item;
    if (!item?.id || converting.value) return;
    if (item.status === 'converted') {
        toast.add({ severity: 'warn', summary: 'Já convertido', life: 2500 });
        return;
    }
    converting.value = true;
    try {
        const { data: userData, error: userErr } = await supabase.auth.getUser();
        if (userErr) throw userErr;
        const ownerId = userData?.user?.id;
        if (!ownerId) throw new Error('Sessão inválida.');

        const tenantId = tenantStore.activeTenantId || tenantStore.tenantId || null;
        if (!tenantId) throw new Error('Tenant não inicializado.');

        const responsibleMemberId = await getResponsibleMemberId(tenantId, ownerId);

        const cleanStr = (v) => { const s = String(v ?? '').trim(); return s ? s : null; };
        const digitsOnly = (v) => { const d = String(v ?? '').replace(/\D/g, ''); return d ? d : null; };
        const intakeAvatar = cleanStr(item.avatar_url) || cleanStr(item.foto_url) || cleanStr(item.photo_url) || null;

        const patientPayload = {
            tenant_id: tenantId,
            responsible_member_id: responsibleMemberId,
            owner_id: ownerId,
            nome_completo: cleanStr(fNome(item)),
            email_principal: cleanStr(fEmail(item))?.toLowerCase() || null,
            email_alternativo: cleanStr(fEmailAlt2(item))?.toLowerCase() || null,
            telefone: digitsOnly(fTel(item)),
            telefone_alternativo: digitsOnly(fTelAlt(item)),
            data_nascimento: normalizeBirthToISO(fNasc(item)),
            naturalidade: cleanStr(fNaturalidade(item)),
            genero: cleanStr(fGenero(item)),
            estado_civil: cleanStr(fEstadoCivil(item)),
            cpf: digitsOnly(item.cpf),
            rg: cleanStr(item.rg),
            pais: cleanStr(fPais(item)) || 'Brasil',
            cep: digitsOnly(fCep(item)),
            cidade: cleanStr(fCidade(item)),
            estado: cleanStr(fEstado(item)) || 'SP',
            endereco: cleanStr(fEndereco(item)),
            numero: cleanStr(fNumero(item)),
            bairro: cleanStr(fBairro(item)),
            complemento: cleanStr(fComplemento(item)),
            escolaridade: cleanStr(fEscolaridade(item)),
            profissao: cleanStr(fProf(item)),
            onde_nos_conheceu: cleanStr(fOndeConheceu(item)),
            encaminhado_por: cleanStr(fEncaminhado(item)),
            observacoes: cleanStr(fObs(item)),
            notas_internas: cleanStr(item.notas_internas || item.notes),
            avatar_url: intakeAvatar
        };
        Object.keys(patientPayload).forEach((k) => {
            if (patientPayload[k] === undefined) delete patientPayload[k];
        });

        const { data: created, error: insErr } = await supabase.from('patients')
            .insert(patientPayload).select('id').single();
        if (insErr) throw insErr;
        const patientId = created?.id;
        if (!patientId) throw new Error('Falha ao obter ID do paciente.');

        const { error: upErr } = await supabase.from('patient_intake_requests')
            .update({ status: 'converted', converted_patient_id: patientId, updated_at: new Date().toISOString() })
            .eq('id', item.id);
        if (upErr) throw upErr;

        toast.add({ severity: 'success', summary: 'Convertido em paciente', life: 2500 });
        closeDlg();
        await fetchIntakes();
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Falha ao converter', detail: e?.message, life: 4500 });
    } finally {
        converting.value = false;
    }
}

onMounted(async () => {
    if (typeof window !== 'undefined' && window.matchMedia) {
        _mqMobile = window.matchMedia('(max-width: 1023px)');
        isMobile.value = _mqMobile.matches;
        _mqMobile.addEventListener('change', _onMqMobileChange);
    }
    if (typeof tenantStore.loadSessionAndTenant === 'function') {
        await tenantStore.loadSessionAndTenant();
    }
    await fetchIntakes();
});
onBeforeUnmount(() => {
    if (_mqMobile) _mqMobile.removeEventListener('change', _onMqMobileChange);
});
</script>

<template>
    <aside
        class="mcr-mobile-drawer"
        :class="{ 'is-open': drawerOpen }"
        v-show="isMobile"
        aria-label="Estatísticas e filtros"
    >
        <div id="mcr-mobile-drawer-target" class="mcr-mobile-drawer__scroll" />
    </aside>
    <Transition name="mcr-drawer-fade">
        <div
            v-if="isMobile && drawerOpen"
            class="mcr-mobile-drawer__backdrop"
            @click="fecharDrawer"
        />
    </Transition>

    <section class="mcr-page">
        <header class="mcr-page__head">
            <button
                class="mcr-menu-btn mcr-menu-btn--mobile-only"
                v-tooltip.bottom="'Estatísticas & filtros'"
                @click="toggleDrawer"
            >
                <i class="pi pi-bars" />
                <span>Menu Cadastros</span>
            </button>
            <div class="mcr-page__title">
                <i class="pi pi-inbox text-amber-300" />
                <span>Cadastros recebidos</span>
                <span class="mcr-page__count">{{ filtered.length }}</span>
            </div>
            <div class="mcr-page__actions">
                <button
                    class="mcr-head-btn"
                    v-tooltip.bottom="'Recarregar'"
                    :disabled="loading"
                    @click="fetchIntakes"
                >
                    <i :class="loading ? 'pi pi-spin pi-spinner' : 'pi pi-refresh'" />
                </button>
                <button class="mcr-close" v-tooltip.bottom="'Voltar (Esc)'" @click="emit('close')">
                    <i class="pi pi-times" />
                </button>
            </div>
        </header>

        <div class="mcr-body">
            <Teleport to="#mcr-mobile-drawer-target" :disabled="!isMobile">
            <aside class="mcr-side">
                <!-- Stats -->
                <div class="mcr-w">
                    <div class="mcr-w__head">
                        <span class="mcr-w__title"><i class="pi pi-chart-bar" /> Estatísticas</span>
                    </div>
                    <div class="mcr-stats">
                        <template v-if="carregandoInicial">
                            <div v-for="i in 4" :key="`stsk-${i}`" class="mcr-stat" aria-busy="true">
                                <div class="mcr-stat__val melissa-skeleton melissa-skeleton--number" />
                                <div class="mcr-stat__lbl melissa-skeleton melissa-skeleton--text" style="width: 60%; margin-top: 6px;" />
                            </div>
                        </template>
                        <div
                            v-for="s in stats"
                            v-else
                            :key="s.key"
                            class="mcr-stat"
                            :class="`is-${s.cls}`"
                        >
                            <div class="mcr-stat__val">{{ s.value }}</div>
                            <div class="mcr-stat__lbl">{{ s.label }}</div>
                        </div>
                    </div>
                </div>

                <!-- Filtro de status -->
                <div class="mcr-w">
                    <div class="mcr-w__head">
                        <span class="mcr-w__title"><i class="pi pi-filter" /> Status</span>
                    </div>
                    <div class="mcr-side__list">
                        <button
                            v-for="o in STATUS_FILTER_OPTIONS"
                            :key="o.key"
                            class="mcr-side__item"
                            :class="[`is-${o.key}`, { 'is-active': statusFilter === o.key }]"
                            @click="toggleStatusFilter(o.key)"
                        >
                            <i :class="o.icon" />
                            <span>{{ o.label }}</span>
                        </button>
                    </div>
                </div>

                <!-- Busca -->
                <div class="mcr-w">
                    <div class="mcr-w__head">
                        <span class="mcr-w__title"><i class="pi pi-search" /> Buscar</span>
                    </div>
                    <input
                        v-model="busca"
                        type="text"
                        placeholder="Nome, email ou telefone…"
                        class="mcr-search__input"
                    />
                </div>
            </aside>
            </Teleport>

            <div class="mcr-main">
                <div class="mcr-list">
                    <template v-if="carregandoInicial">
                        <div v-for="i in 5" :key="`csk-${i}`" class="mcr-card mcr-card--skeleton" aria-busy="true">
                            <span class="mcr-card__avatar melissa-skeleton melissa-skeleton--avatar" />
                            <div style="flex:1; display:flex; flex-direction:column; gap:6px;">
                                <span class="melissa-skeleton melissa-skeleton--title" :style="{ width: `${50 + (i * 9) % 30}%` }" />
                                <span class="melissa-skeleton melissa-skeleton--text" style="width: 60%;" />
                            </div>
                        </div>
                    </template>

                    <div v-else-if="filtered.length === 0" class="mcr-empty">
                        <i class="pi pi-inbox mcr-empty__icon" />
                        <div class="mcr-empty__title">Nenhum cadastro encontrado</div>
                        <div class="mcr-empty__hint">
                            <template v-if="busca || statusFilter">Ajuste os filtros pra ver mais.</template>
                            <template v-else>Cadastros vindos do agendador externo aparecem aqui.</template>
                        </div>
                    </div>

                    <button
                        v-for="r in filteredPaginated"
                        v-else
                        :key="r.id"
                        class="mcr-card"
                        :class="statusClass(r.status)"
                        @click="openDetails(r)"
                    >
                        <span class="mcr-card__avatar">
                            <img v-if="avatarUrl(r)" :src="avatarUrl(r)" :alt="fNome(r) || 'Avatar'" />
                            <span v-else>{{ pacienteIniciais(fNome(r)) }}</span>
                        </span>
                        <div class="mcr-card__main">
                            <div class="mcr-card__name-row">
                                <span class="mcr-card__name">{{ fNome(r) || '—' }}</span>
                                <span class="mcr-card__badge" :class="statusClass(r.status)">
                                    {{ statusLabel(r.status) }}
                                </span>
                            </div>
                            <div class="mcr-card__meta">
                                <span v-if="fEmail(r)"><i class="pi pi-envelope" /> {{ fEmail(r) }}</span>
                                <span v-if="fTel(r)"><i class="pi pi-phone" /> {{ fmtPhoneBR(fTel(r)) }}</span>
                            </div>
                        </div>
                        <div class="mcr-card__time">
                            <i class="pi pi-clock" /> {{ fmtRelative(r.created_at) }}
                        </div>
                    </button>
                </div>

                <Paginator
                    v-if="!carregandoInicial && filtered.length > 0"
                    class="mcr-paginator"
                    :rows="rowsMCR"
                    :totalRecords="filtered.length"
                    :first="(pageMCR - 1) * rowsMCR"
                    :rowsPerPageOptions="PAGE_SIZE_OPTIONS"
                    template="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
                    currentPageReportTemplate="{first}–{last} de {totalRecords}"
                    @page="onPageMCRChange"
                />
            </div>
        </div>

        <!-- Dialog detalhes -->
        <Dialog
            :visible="dlg.open"
            modal
            dismissable-mask
            :style="{ width: '640px', maxWidth: '94vw' }"
            :header="fNome(dlg.item) || 'Cadastro'"
            @update:visible="(v) => !v && closeDlg()"
        >
            <div v-if="dlg.item" class="flex flex-col gap-4">
                <!-- Avatar + status + ações principais -->
                <div class="flex items-start gap-3">
                    <div class="mcr-dlg__avatar">
                        <img v-if="dlgAvatarUrl" :src="dlgAvatarUrl" :alt="fNome(dlg.item)" />
                        <span v-else>{{ pacienteIniciais(fNome(dlg.item)) }}</span>
                    </div>
                    <div class="flex-1 min-w-0">
                        <div class="text-sm font-bold">{{ fNome(dlg.item) }}</div>
                        <div class="text-xs text-[var(--text-color-secondary)] mt-1">
                            <span class="mcr-card__badge" :class="statusClass(dlg.item.status)">{{ statusLabel(dlg.item.status) }}</span>
                            · Criado {{ fmtRelative(dlg.item.created_at) }}
                        </div>
                    </div>
                </div>

                <!-- Seções -->
                <div v-for="sec in dlgSections" :key="sec.title" class="flex flex-col gap-1">
                    <div class="text-[0.62rem] uppercase tracking-wider font-semibold text-[var(--text-color-secondary)] opacity-70">{{ sec.title }}</div>
                    <div class="grid grid-cols-2 gap-x-4 gap-y-1 text-xs">
                        <template v-for="r in sec.rows" :key="r.label">
                            <div class="text-[var(--text-color-secondary)]">{{ r.label }}</div>
                            <div class="text-[var(--text-color)]">{{ r.value }}</div>
                        </template>
                    </div>
                </div>

                <!-- Motivo da rejeição -->
                <div v-if="dlg.item.status !== 'converted'" class="flex flex-col gap-1">
                    <label class="text-[0.62rem] uppercase tracking-wider font-semibold text-[var(--text-color-secondary)] opacity-70">
                        Motivo da rejeição (opcional)
                    </label>
                    <Textarea v-model="dlg.reject_note" autoResize rows="2" class="w-full text-xs" :disabled="dlg.saving" />
                </div>
            </div>
            <template #footer>
                <div class="flex items-center gap-2 w-full">
                    <Button label="Fechar" text @click="closeDlg" />
                    <div class="flex-1" />
                    <Button
                        v-if="dlg.item && dlg.item.status !== 'rejected' && dlg.item.status !== 'converted'"
                        label="Rejeitar"
                        severity="danger"
                        outlined
                        :disabled="dlg.saving || converting"
                        @click="markRejected"
                    />
                    <Button
                        v-if="dlg.item && dlg.item.status !== 'converted'"
                        :label="converting ? 'Convertendo…' : 'Converter em paciente'"
                        :loading="converting"
                        :disabled="dlg.saving || converting"
                        @click="convertToPatient"
                    />
                </div>
            </template>
        </Dialog>
    </section>
</template>

<style scoped>
.mcr-page {
    position: absolute;
    inset: 6px 6px calc(var(--m-dock-h, 76px) + 6px) 6px;
    z-index: 40;
    display: flex;
    flex-direction: column;
    background: var(--m-bg-medium);
    backdrop-filter: blur(32px) saturate(160%);
    -webkit-backdrop-filter: blur(32px) saturate(160%);
    border: 1px solid var(--m-border);
    border-radius: 18px;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4);
    overflow: hidden;
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    color: var(--m-text);
    animation: mcr-page-enter 240ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
@keyframes mcr-page-enter {
    from { opacity: 0; transform: scale(0.985); }
    to   { opacity: 1; transform: scale(1); }
}

.mcr-page__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--m-border);
    flex-shrink: 0;
    gap: 10px;
}
.mcr-page__title {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 1rem;
    font-weight: 500;
}
.mcr-page__title > span:not(.mcr-page__count) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mcr-page__count {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--m-accent);
    background: var(--m-accent-soft);
    border: 1px solid color-mix(in srgb, var(--m-accent) 35%, transparent);
    padding: 2px 8px;
    border-radius: 999px;
}
.mcr-page__actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.mcr-close, .mcr-head-btn {
    width: 32px; height: 32px;
    display: grid; place-items: center;
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    color: var(--m-text);
    border-radius: 9px;
    cursor: pointer;
    font-family: inherit;
    transition: background-color 140ms ease;
}
.mcr-close:hover, .mcr-head-btn:hover { background: var(--m-bg-soft-hover); }
.mcr-head-btn > i { font-size: 0.85rem; }

.mcr-menu-btn {
    display: none;
    height: 32px;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    background: var(--m-accent);
    border: 1px solid var(--m-accent);
    color: white;
    padding: 0 11px;
    border-radius: 9px;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    transition: background-color 140ms ease, transform 140ms ease;
}
.mcr-menu-btn:hover {
    background: color-mix(in srgb, var(--m-accent) 88%, white);
    transform: translateY(-1px);
}

.mcr-body {
    flex: 1;
    display: flex;
    min-height: 0;
    gap: 12px;
    padding: 12px;
}
.mcr-side {
    width: 280px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
    overflow-y: auto;
}
.mcr-side::-webkit-scrollbar { width: 5px; }
.mcr-side::-webkit-scrollbar-thumb {
    background: var(--m-border-strong);
    border-radius: 3px;
}

/* Card-base — alinhado com .ma-w (MelissaAgenda) e .mp-w (MelissaPacientes):
   surface --m-bg-medium pra destacar do bg da página/dialog (ambos --m-bg-soft). */
.mcr-w {
    background: var(--m-bg-medium);
    border: 1px solid var(--m-border);
    border-radius: 12px;
    padding: 12px;
}
.mcr-w__head { margin-bottom: 10px; }
.mcr-w__title {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.78rem;
    font-weight: 600;
}
.mcr-w__title > i { color: var(--m-text-muted); font-size: 0.78rem; }

.mcr-stats {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 6px;
}
.mcr-stat {
    /* Mais sutil que o card-pai (.mcr-w em --m-bg-medium) pra criar contraste
       interno. Antes usava --m-bg-medium e ficava igual ao pai. */
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    border-radius: 10px;
    padding: 8px 10px;
}
.mcr-stat__val {
    font-size: 1.1rem;
    font-weight: 600;
    line-height: 1.1;
}
.mcr-stat__lbl {
    font-size: 0.65rem;
    color: var(--m-text-muted);
    margin-top: 4px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.mcr-stat.is-warn .mcr-stat__val { color: rgb(251, 191, 36); }
.mcr-stat.is-ok .mcr-stat__val { color: rgb(74, 222, 128); }

.mcr-side__list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.mcr-side__item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    background: transparent;
    border: 1px solid transparent;
    color: var(--m-text);
    border-radius: 10px;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.82rem;
    text-align: left;
    transition: background-color 140ms ease, border-color 140ms ease;
}
.mcr-side__item:hover { background: var(--m-bg-soft-hover); }
.mcr-side__item.is-active.is-new {
    background: rgba(251, 191, 36, 0.08);
    border-color: rgba(251, 191, 36, 0.35);
}
.mcr-side__item.is-active.is-converted {
    background: rgba(74, 222, 128, 0.08);
    border-color: rgba(74, 222, 128, 0.35);
}
.mcr-side__item.is-active.is-rejected {
    background: rgba(248, 113, 113, 0.08);
    border-color: rgba(248, 113, 113, 0.35);
}
.mcr-side__item > i { font-size: 0.75rem; color: var(--m-text-muted); width: 14px; text-align: center; }
.mcr-side__item.is-active.is-new > i { color: rgb(251, 191, 36); }
.mcr-side__item.is-active.is-converted > i { color: rgb(74, 222, 128); }
.mcr-side__item.is-active.is-rejected > i { color: rgb(248, 113, 113); }

.mcr-search__input {
    width: 100%;
    /* Mais sutil que o card-pai pra ler como input dentro do card. */
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    color: var(--m-text);
    padding: 8px 12px;
    border-radius: 9px;
    font-size: 0.82rem;
    font-family: inherit;
    outline: none;
}
.mcr-search__input:focus { border-color: var(--m-border-strong); background: var(--m-bg-soft-hover); }

.mcr-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mcr-list {
    flex: 1;
    overflow-y: auto;
    padding: 0 4px 4px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.mcr-list::-webkit-scrollbar { width: 5px; }
.mcr-list::-webkit-scrollbar-thumb {
    background: var(--m-border-strong);
    border-radius: 3px;
}

/* Paginator no rodapé da col 2 — fixo (fora do scroll), com seletor de
   tamanho (10/20/50/100). Mesma estética do .mp-paginator (MelissaPacientes). */
.mcr-paginator.p-paginator {
    background: transparent;
    border: none;
    border-top: 1px solid var(--m-border);
    padding: 8px 12px;
    margin-top: 4px;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 6px;
}
.mcr-paginator.p-paginator .p-paginator-current {
    color: var(--m-text-muted);
    font-size: 0.78rem;
    background: transparent;
    border: none;
    padding: 0 4px;
    height: 30px;
    min-width: auto;
}
.mcr-paginator.p-paginator .p-paginator-first,
.mcr-paginator.p-paginator .p-paginator-prev,
.mcr-paginator.p-paginator .p-paginator-next,
.mcr-paginator.p-paginator .p-paginator-last,
.mcr-paginator.p-paginator .p-paginator-page {
    min-width: 30px;
    height: 30px;
    color: var(--m-text);
    background: transparent;
    border: 1px solid var(--m-border);
    border-radius: 8px;
    font-size: 0.8rem;
    transition: background-color 140ms ease, border-color 140ms ease;
}
.mcr-paginator.p-paginator .p-paginator-page.p-paginator-page-selected {
    background: var(--m-accent-soft);
    border-color: var(--m-accent-strong);
    color: var(--m-accent);
}
.mcr-paginator.p-paginator .p-paginator-first:not(.p-disabled):hover,
.mcr-paginator.p-paginator .p-paginator-prev:not(.p-disabled):hover,
.mcr-paginator.p-paginator .p-paginator-next:not(.p-disabled):hover,
.mcr-paginator.p-paginator .p-paginator-last:not(.p-disabled):hover,
.mcr-paginator.p-paginator .p-paginator-page:not(.p-paginator-page-selected):hover {
    background: var(--m-bg-soft-hover);
    border-color: var(--m-border-strong);
}
.mcr-paginator.p-paginator .p-paginator-first.p-disabled,
.mcr-paginator.p-paginator .p-paginator-prev.p-disabled,
.mcr-paginator.p-paginator .p-paginator-next.p-disabled,
.mcr-paginator.p-paginator .p-paginator-last.p-disabled {
    opacity: 0.35;
}
.mcr-paginator.p-paginator .p-select {
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    border-radius: 8px;
    height: 30px;
    font-size: 0.78rem;
    color: var(--m-text);
}
.mcr-paginator.p-paginator .p-select:hover { border-color: var(--m-border-strong); }
.mcr-paginator.p-paginator .p-select-label {
    padding: 0 8px;
    color: var(--m-text);
    font-size: 0.78rem;
}

.mcr-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    background: var(--m-bg-soft);
    border: 1px solid var(--m-border);
    border-radius: 10px;
    cursor: pointer;
    transition: background-color 140ms ease, border-color 140ms ease, transform 140ms ease;
    text-align: left;
    font-family: inherit;
    color: var(--m-text);
}
.mcr-card:hover {
    background: var(--m-bg-soft-hover);
    border-color: var(--m-border-strong);
    transform: translateY(-1px);
}
.mcr-card.is-new { border-left: 3px solid rgb(251, 191, 36); }
.mcr-card.is-done { opacity: 0.75; }
.mcr-card.is-rejected { opacity: 0.55; }
.mcr-card--skeleton { cursor: default; pointer-events: none; opacity: 0.95; }
.mcr-card--skeleton:hover { background: var(--m-bg-soft); transform: none; }

.mcr-card__avatar {
    width: 40px; height: 40px;
    border-radius: 50%;
    background: var(--m-accent-strong);
    border: 1px solid var(--m-accent);
    color: white;
    font-size: 0.78rem;
    font-weight: 600;
    display: grid; place-items: center;
    flex-shrink: 0;
    overflow: hidden;
}
.mcr-card__avatar img { width: 100%; height: 100%; object-fit: cover; }

.mcr-card__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mcr-card__name-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.mcr-card__name {
    font-size: 0.92rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mcr-card__badge {
    display: inline-flex;
    align-items: center;
    font-size: 0.62rem;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border: 1px solid;
}
.mcr-card__badge.is-new {
    color: rgb(251, 191, 36);
    background: rgba(251, 191, 36, 0.12);
    border-color: rgba(251, 191, 36, 0.3);
}
.mcr-card__badge.is-done {
    color: rgb(74, 222, 128);
    background: rgba(74, 222, 128, 0.12);
    border-color: rgba(74, 222, 128, 0.3);
}
.mcr-card__badge.is-rejected {
    color: rgb(248, 113, 113);
    background: rgba(248, 113, 113, 0.12);
    border-color: rgba(248, 113, 113, 0.3);
}
.mcr-card__meta {
    display: flex;
    gap: 14px;
    margin-top: 4px;
    font-size: 0.7rem;
    color: var(--m-text-muted);
}
.mcr-card__meta i { margin-right: 5px; font-size: 0.65rem; }
.mcr-card__time {
    flex-shrink: 0;
    font-size: 0.7rem;
    color: var(--m-text-muted);
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.mcr-card__time i { font-size: 0.65rem; }

.mcr-empty {
    margin: 24px 0;
    padding: 56px 28px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    color: var(--m-text-muted);
    border: 2px dashed var(--m-border-strong);
    border-radius: 12px;
    background: color-mix(in srgb, var(--m-bg-soft) 40%, transparent);
    gap: 8px;
}
.mcr-empty__icon { font-size: 2rem; color: var(--m-text-faint); margin-bottom: 4px; }
.mcr-empty__title { font-size: 0.92rem; font-weight: 600; color: var(--m-text); }
.mcr-empty__hint { font-size: 0.78rem; }

/* Dialog avatar */
.mcr-dlg__avatar {
    width: 56px; height: 56px;
    border-radius: 50%;
    background: var(--m-accent-strong);
    border: 1px solid var(--m-accent);
    color: white;
    font-size: 1rem;
    font-weight: 600;
    display: grid; place-items: center;
    flex-shrink: 0;
    overflow: hidden;
}
.mcr-dlg__avatar img { width: 100%; height: 100%; object-fit: cover; }

/* Drawer mobile */
.mcr-mobile-drawer {
    position: fixed;
    top: 0; left: 0;
    height: 100vh;
    height: 100dvh;
    width: min(360px, 88vw);
    z-index: 80;
    background: var(--m-bg-medium);
    backdrop-filter: blur(28px) saturate(160%);
    -webkit-backdrop-filter: blur(28px) saturate(160%);
    border-right: 1px solid var(--m-border);
    transform: translateX(-100%);
    transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1);
    color: var(--m-text);
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
.mcr-mobile-drawer.is-open { transform: translateX(0); }
.mcr-mobile-drawer__scroll {
    height: 100%;
    overflow-y: auto;
    padding: 12px 12px 24px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.mcr-mobile-drawer__scroll::-webkit-scrollbar { width: 5px; }
.mcr-mobile-drawer__scroll::-webkit-scrollbar-thumb {
    background: var(--m-border-strong);
    border-radius: 3px;
}
.mcr-mobile-drawer__scroll .mcr-side {
    width: 100%;
    height: auto;
    overflow: visible;
    padding: 0;
}
.mcr-mobile-drawer__backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    z-index: 79;
}
.mcr-drawer-fade-enter-active,
.mcr-drawer-fade-leave-active { transition: opacity 200ms ease; }
.mcr-drawer-fade-enter-from,
.mcr-drawer-fade-leave-to { opacity: 0; }

@media (max-width: 1023px) {
    .mcr-body { flex-direction: column; padding: 8px; }
    .mcr-main { width: 100%; }
    .mcr-page__title > span:first-of-type { display: none; }
    .mcr-menu-btn--mobile-only { display: inline-flex; }
    .mcr-card__time { display: none; }
}
</style>
