<!--
|--------------------------------------------------------------------------
| Agência PSI — Drawer global de conversa
|--------------------------------------------------------------------------
| Uso: <ConversationDrawer /> no AppLayout. Controlado via store:
|   const store = useConversationDrawerStore();
|   store.openForPatient(patientId);
|   store.openForThread(thread);
|--------------------------------------------------------------------------
-->
<script setup>
import { ref, computed, nextTick, watch, onMounted, onBeforeUnmount } from 'vue';
import { useToast } from 'primevue/usetoast';
import { useConfirm } from 'primevue/useconfirm';
import { useConversationDrawerStore } from '@/stores/conversationDrawerStore';
import { useConversationNotes } from '@/composables/useConversationNotes';
import { useConversationTags } from '@/composables/useConversationTags';
import { useConversationAssignment } from '@/composables/useConversationAssignment';
import { supabase } from '@/lib/supabase/client';
import { tenantDb } from '@/lib/supabase/tenantClient';
import ComponentCadastroRapido from '@/components/ComponentCadastroRapido.vue';

const toast = useToast();
const confirm = useConfirm();
const store = useConversationDrawerStore();
const notesApi = useConversationNotes();
const tagsApi = useConversationTags();
const assignApi = useConversationAssignment();
const tagsPopover = ref(null);

// ── Current user (pra saber se pode editar/deletar notas próprias) ────
const currentUserId = ref(null);
supabase.auth.getUser().then(({ data }) => { currentUserId.value = data?.user?.id ?? null; });

// ── Notas internas ────────────────────────────────────────────
const notesOpen = ref(false);
const newNoteText = ref('');
const editingNoteId = ref(null);
const editingText = ref('');

// ── Converter número desconhecido em paciente (CRM 3.5) ────
const quickPatientDialog = ref(false);
const linkPatientDialog = ref(false);
const linkPatientOptions = ref([]);
const linkPatientLoading = ref(false);
const linkPatientSelected = ref(null);
const linkingPatient = ref(false);

// Strip "55" DDI prefix se tiver (InputMask espera 10-11 dígitos BR)
function phoneForForm(raw) {
    const d = String(raw || '').replace(/\D/g, '');
    if (d.length === 13 && d.startsWith('55')) return d.slice(2);
    if (d.length === 12 && d.startsWith('55')) return d.slice(2);
    return d;
}

function openConvertToPatient() {
    quickPatientDialog.value = true;
}

function openLinkPatient() {
    linkPatientSelected.value = null;
    linkPatientDialog.value = true;
    loadPatients();
}

async function loadPatients() {
    const tenantId = store.thread?.tenant_id;
    if (!tenantId) return;
    linkPatientLoading.value = true;
    try {
        // Carrega todos os pacientes do tenant (até 500) — filter é client-side
        const { data, error } = await tenantDb().from('patients')
            .select('id, nome_completo, telefone, email_principal, status')
            .order('nome_completo', { ascending: true })
            .limit(500);
        if (error) throw error;
        // Formata label combinado pra filter achar
        linkPatientOptions.value = (data || []).map((p) => ({
            ...p,
            _label: `${p.nome_completo}${p.telefone ? ' · ' + formatPhoneShort(p.telefone) : ''}${p.email_principal ? ' · ' + p.email_principal : ''}`
        }));
    } catch (e) {
        console.error('[ConversationDrawer] load patients:', e?.message);
        linkPatientOptions.value = [];
        toast.add({ severity: 'error', summary: 'Erro', detail: 'Falha ao carregar pacientes: ' + e?.message, life: 4000 });
    } finally {
        linkPatientLoading.value = false;
    }
}

async function confirmLinkPatient() {
    const patient = linkPatientSelected.value;
    if (!patient?.id || !store.thread?.contact_number) return;
    linkingPatient.value = true;
    try {
        const phone = store.thread.contact_number;
        const tenantId = store.thread.tenant_id;

        // 1) Vincula conversation_messages
        const { error } = await tenantDb().from('conversation_messages')
            .update({ patient_id: patient.id })
            .or(`from_number.eq.${phone},to_number.eq.${phone}`)
            .is('patient_id', null);
        if (error) throw error;

        // 2) Adiciona telefone WhatsApp no contact_phones (se não existir ainda)
        await upsertWhatsappForExisting(tenantId, patient.id, phone);

        store.thread.patient_id = patient.id;
        store.thread.patient_name = patient.nome_completo;
        store.thread.thread_key = patient.id;
        for (const m of store.messages) {
            if (!m.patient_id) m.patient_id = patient.id;
        }
        linkPatientDialog.value = false;
        toast.add({
            severity: 'success',
            summary: 'Conversa vinculada',
            detail: `${patient.nome_completo} agora está ligado a essa conversa. Número salvo como WhatsApp (vinculado).`,
            life: 3500
        });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao vincular', detail: e?.message, life: 4000 });
    } finally {
        linkingPatient.value = false;
    }
}

// Helper: adiciona telefone WhatsApp (vinculado) ao paciente existente.
// Se já tem um telefone com o mesmo número, só marca como vinculado em vez de duplicar.
async function upsertWhatsappForExisting(tenantId, patientId, threadPhone) {
    if (!tenantId || !patientId || !threadPhone) return;
    try {
        const phoneDigits = String(threadPhone).replace(/\D/g, '');

        // Busca se já tem esse número cadastrado
        const { data: existing } = await tenantDb().from('contact_phones')
            .select('id, contact_type_id, whatsapp_linked_at')
            .eq('entity_type', 'patient')
            .eq('entity_id', patientId)
            .eq('number', phoneDigits)
            .limit(1)
            .maybeSingle();

        if (existing) {
            // Atualiza vinculado_at se ainda não tinha
            if (!existing.whatsapp_linked_at) {
                await tenantDb().from('contact_phones')
                    .update({ whatsapp_linked_at: new Date().toISOString() })
                    .eq('id', existing.id);
            }
            return;
        }

        // Não tem — cria novo com type='whatsapp'
        const { data: types } = await tenantDb().from('contact_types')
            .select('id, slug')
            .eq('is_system', true)
            .eq('slug', 'whatsapp')
            .maybeSingle();
        const whatsappTypeId = types?.id;
        if (!whatsappTypeId) return;

        await tenantDb().from('contact_phones').insert({
            entity_type: 'patient',
            entity_id: patientId,
            contact_type_id: whatsappTypeId,
            number: phoneDigits,
            is_primary: false,
            whatsapp_linked_at: new Date().toISOString(),
            position: 100
        });
    } catch (e) {
        console.warn('[ConversationDrawer] upsert whatsapp contact_phones:', e?.message);
    }
}

function formatPhoneShort(p) {
    const s = String(p || '').replace(/\D/g, '');
    if (s.length === 11) return `(${s.slice(0, 2)}) ${s.slice(2, 7)}-${s.slice(7)}`;
    if (s.length === 10) return `(${s.slice(0, 2)}) ${s.slice(2, 6)}-${s.slice(6)}`;
    if (s.length === 13 && s.startsWith('55')) return `(${s.slice(2, 4)}) ${s.slice(4, 9)}-${s.slice(9)}`;
    return p;
}

// Após criar paciente: vincula conversation_messages + registra telefone WhatsApp em contact_phones
async function onPatientCreated(row) {
    const newPatientId = row?.id;
    const phone = store.thread?.contact_number;
    const tenantId = store.thread?.tenant_id;
    if (!newPatientId || !phone) {
        toast.add({ severity: 'warn', summary: 'Paciente criado', detail: 'Mas não foi possível vincular a conversa. Recarregue.', life: 4000 });
        return;
    }
    try {
        // 1) Vincula TODAS as mensagens do thread (anon) a esse patient_id
        const { error: msgErr } = await tenantDb().from('conversation_messages')
            .update({ patient_id: newPatientId })
            .or(`from_number.eq.${phone},to_number.eq.${phone}`)
            .is('patient_id', null);
        if (msgErr) throw msgErr;

        // 2) Insere telefone WhatsApp em contact_phones (se ainda não tem)
        //    O Celular primary já foi criado pelo trigger quando cadastrou via ComponentCadastroRapido? NÃO.
        //    ComponentCadastroRapido insere em patients.telefone direto. Vou adicionar contact_phones AGORA.
        await insertWhatsappContactPhone(tenantId, newPatientId, phone, row.telefone);

        // 3) Atualiza o store localmente (thread_key vai mudar pra UUID)
        store.thread.patient_id = newPatientId;
        store.thread.patient_name = row.nome_completo || row.nome || null;
        store.thread.thread_key = newPatientId;
        for (const m of store.messages) {
            if (!m.patient_id) m.patient_id = newPatientId;
        }
        toast.add({
            severity: 'success',
            summary: 'Paciente criado e vinculado',
            detail: `${store.thread.patient_name} agora está ligado a essa conversa.`,
            life: 3500
        });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao vincular', detail: e?.message || 'Falha ao atualizar mensagens', life: 4000 });
    }
}

// Helper: insere entries em contact_phones pra novo paciente criado via ComponentCadastroRapido.
// 1) Celular (primary) = telefone do form (se tiver, já diferente do whatsapp)
// 2) WhatsApp com whatsapp_linked_at = phone da thread (se não for igual ao celular)
async function insertWhatsappContactPhone(tenantId, patientId, threadPhone, formPhone) {
    if (!tenantId || !patientId || !threadPhone) return;
    try {
        // Busca tipos system
        const { data: types } = await tenantDb().from('contact_types')
            .select('id, slug')
            .eq('is_system', true);
        const celularType = types?.find((t) => t.slug === 'celular');
        const whatsappType = types?.find((t) => t.slug === 'whatsapp');

        const phoneDigits = String(threadPhone).replace(/\D/g, '');
        const formDigits = String(formPhone || '').replace(/\D/g, '');
        // formPhone vem do quick create sem DDI (10-11 dig); threadPhone com DDI (13 dig).
        // Normaliza: remove DDI 55 pra comparar
        const formNoDdi = formDigits.length >= 12 && formDigits.startsWith('55') ? formDigits.slice(2) : formDigits;
        const threadNoDdi = phoneDigits.length >= 12 && phoneDigits.startsWith('55') ? phoneDigits.slice(2) : phoneDigits;

        const rows = [];

        // Celular primary (from form — o que o user digitou no cadastro rápido)
        if (celularType && formDigits && formDigits.length >= 8) {
            rows.push({
                entity_type: 'patient',
                entity_id: patientId,
                contact_type_id: celularType.id,
                number: formDigits.length < 12 ? '55' + formDigits : formDigits, // garante DDI
                is_primary: true,
                position: 10
            });
        }

        // WhatsApp linked (from thread) — só se diferente do celular
        if (whatsappType && phoneDigits && formNoDdi !== threadNoDdi) {
            rows.push({
                entity_type: 'patient',
                entity_id: patientId,
                contact_type_id: whatsappType.id,
                number: phoneDigits,
                is_primary: false,
                whatsapp_linked_at: new Date().toISOString(),
                position: 20
            });
        } else if (whatsappType && phoneDigits && formNoDdi === threadNoDdi && rows.length > 0) {
            // Mesmo número → marca o celular como também vinculado WhatsApp
            rows[0].whatsapp_linked_at = new Date().toISOString();
        }

        if (rows.length > 0) {
            await tenantDb().from('contact_phones').insert(rows);
        }
    } catch (e) {
        console.warn('[ConversationDrawer] insert whatsapp contact_phones:', e?.message);
        // Não bloqueia o fluxo — paciente já foi criado
    }
}

// ── Resolução de URLs de mídia ─────────────────────────────
// Mensagens de WhatsApp vêm com media_url em dois formatos:
//  1) URL externa (http/https) — Twilio e outras; usa direto
//  2) Path interno do bucket privado whatsapp-media — precisa signed URL
const mediaUrls = ref({}); // { [msgId]: resolvedUrl }

async function ensureMediaUrl(m) {
    if (!m?.id || !m.media_url) return;
    if (mediaUrls.value[m.id]) return;
    const raw = m.media_url;
    if (/^https?:\/\//i.test(raw)) {
        mediaUrls.value[m.id] = raw;
        return;
    }
    // Path interno — gera signed URL (expira em 1h, re-resolvido ao reabrir drawer)
    const { data, error } = await supabase.storage.from('whatsapp-media').createSignedUrl(raw, 3600);
    if (error) {
        console.error('[ConversationDrawer] signed URL error:', error.message);
        mediaUrls.value[m.id] = null;
        return;
    }
    mediaUrls.value[m.id] = data?.signedUrl || null;
}

const composeText = ref('');
const composeTextareaRef = ref(null);
const messagesContainerRef = ref(null);
const templatesPopover = ref(null);
const emojiPopover = ref(null);

const isOpen = computed({
    get: () => store.isOpen,
    set: (v) => { if (!v) store.close(); }
});

const KANBAN_COLUMNS = [
    { key: 'urgent', label: 'Urgente', icon: 'pi pi-exclamation-triangle' },
    { key: 'awaiting_us', label: 'Aguardando resposta', icon: 'pi pi-inbox' },
    { key: 'awaiting_patient', label: 'Aguardando paciente', icon: 'pi pi-hourglass' },
    { key: 'resolved', label: 'Resolvido', icon: 'pi pi-check' }
];

// ── Formatters ─────────────────────────────────────────────
// HH:MM curto pra exibir dentro da bolha (estilo WhatsApp).
function fmtTimeOnly(iso) {
    if (!iso) return '';
    return new Date(iso).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
}

// Iniciais pro avatar circular do header.
function iniciaisChat(name) {
    if (!name) return '?';
    const parts = String(name).trim().split(/\s+/).filter(Boolean);
    if (!parts.length) return '?';
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}

function channelIcon(ch) {
    const map = { whatsapp: 'pi-whatsapp', sms: 'pi-comment', email: 'pi-envelope' };
    return map[ch] || 'pi-comment';
}

function isImage(mime) { return !!mime && mime.startsWith('image/'); }
function isAudio(mime) { return !!mime && mime.startsWith('audio/'); }
function isVideo(mime) { return !!mime && mime.startsWith('video/'); }

function contactLabel() {
    return store.thread?.patient_name || store.thread?.contact_number || 'Desconhecido';
}

function whatsappLink() {
    const num = (store.thread?.contact_number || '').replace(/\D/g, '');
    if (!num) return '';
    return `https://wa.me/${num}`;
}

// ── Auto-scroll ────────────────────────────────────────────
function scrollToBottom() {
    nextTick(() => {
        const el = messagesContainerRef.value;
        if (el) el.scrollTop = el.scrollHeight;
    });
}

watch(() => store.messages.length, () => {
    if (store.isOpen) scrollToBottom();
    // Resolve URLs de novas mensagens com mídia
    for (const m of store.messages) {
        if (m.media_url && !mediaUrls.value[m.id]) ensureMediaUrl(m);
    }
});
watch(() => store.isOpen, (open) => {
    if (open) {
        composeText.value = '';
        scrollToBottom();
        // Re-resolve URLs ao abrir (signed URLs podem ter expirado)
        mediaUrls.value = {};
        for (const m of store.messages) {
            if (m.media_url) ensureMediaUrl(m);
        }
        // Carrega notas, tags e atribuição da thread
        if (store.thread?.thread_key) {
            notesApi.load(store.thread.thread_key);
            tagsApi.loadAllTags();
            tagsApi.loadForThread(store.thread.thread_key);
            assignApi.loadMembers().then(() => assignApi.load(store.thread.thread_key));
        }
    } else {
        notesApi.clear();
        tagsApi.clear();
        assignApi.clear();
        notesOpen.value = false;
        editingNoteId.value = null;
    }
});

// Recarrega notas + tags + atribuição ao trocar de thread sem fechar drawer
watch(() => store.thread?.thread_key, (key) => {
    if (key && store.isOpen) {
        notesApi.load(key);
        tagsApi.loadForThread(key);
        assignApi.load(key);
    }
});

// ── Handlers de atribuição ──────────────────────────────────
async function onAssignChange(newUserId) {
    if (!store.thread?.thread_key) return;
    const res = await assignApi.assign({
        threadKey: store.thread.thread_key,
        patientId: store.thread.patient_id || null,
        contactNumber: store.thread.contact_number || null,
        assignedTo: newUserId || null
    });
    if (res.ok) {
        toast.add({
            severity: 'success',
            summary: newUserId ? 'Conversa atribuída' : 'Atribuição removida',
            life: 2000
        });
    } else {
        toast.add({ severity: 'error', summary: 'Erro', detail: res.error || 'Falha ao atribuir', life: 3500 });
    }
}

async function assignToMe() {
    const uid = currentUserId.value;
    if (!uid) return;
    await onAssignChange(uid);
}

// ── Handlers de tags ────────────────────────────────────────
function openTagsPopover(ev) {
    tagsPopover.value?.toggle(ev);
}

async function onToggleTag(tagId) {
    if (!store.thread?.thread_key) return;
    const res = await tagsApi.toggleOnThread(store.thread.thread_key, tagId);
    if (!res.ok) {
        toast.add({ severity: 'error', summary: 'Erro', detail: res.error || 'Falha ao atualizar tag', life: 3500 });
    }
}

// ── Handlers de notas ─────────────────────────────────────────
async function addNote() {
    const text = newNoteText.value.trim();
    if (!text || !store.thread) return;
    const res = await notesApi.create({
        threadKey: store.thread.thread_key,
        patientId: store.thread.patient_id || null,
        contactNumber: store.thread.contact_number || null,
        body: text
    });
    if (res.ok) {
        newNoteText.value = '';
        toast.add({ severity: 'success', summary: 'Nota adicionada', life: 1800 });
    } else {
        toast.add({ severity: 'error', summary: 'Erro', detail: res.error || 'Falha ao salvar nota', life: 3500 });
    }
}

function startEditNote(note) {
    editingNoteId.value = note.id;
    editingText.value = note.body;
}

function cancelEditNote() {
    editingNoteId.value = null;
    editingText.value = '';
}

async function saveEditNote(id) {
    const res = await notesApi.update(id, editingText.value);
    if (res.ok) {
        editingNoteId.value = null;
        editingText.value = '';
        toast.add({ severity: 'success', summary: 'Nota atualizada', life: 1800 });
    } else {
        toast.add({ severity: 'error', summary: 'Erro', detail: res.error || 'Falha ao atualizar', life: 3500 });
    }
}

function confirmDeleteNote(id) {
    confirm.require({
        group: 'conversation-drawer',
        message: 'Remover esta nota? Essa ação não pode ser desfeita.',
        header: 'Remover nota',
        icon: 'pi pi-exclamation-triangle',
        acceptLabel: 'Remover',
        rejectLabel: 'Cancelar',
        acceptClass: 'p-button-danger',
        accept: async () => {
            const res = await notesApi.remove(id);
            if (res.ok) {
                toast.add({ severity: 'success', summary: 'Nota removida', life: 1800 });
            } else {
                toast.add({ severity: 'error', summary: 'Erro', detail: res.error, life: 3500 });
            }
        }
    });
}

function fmtNoteDate(iso) {
    if (!iso) return '';
    const d = new Date(iso);
    const today = new Date();
    const isToday = d.toDateString() === today.toDateString();
    if (isToday) {
        return 'Hoje, ' + d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
    }
    return d.toLocaleString('pt-BR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
}

// ── Injeta botão de download no toolbar do <Image preview> ────
// PrimeVue Image não expõe slot pra adicionar buttons no preview,
// então observamos o DOM: quando o toolbar aparece, inserimos o botão.
let _toolbarObserver = null;

function triggerImageDownload(src) {
    if (!src) return;
    // Fetch + blob pra forçar download (atributo 'download' não funciona cross-origin)
    fetch(src)
        .then((r) => r.blob())
        .then((blob) => {
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            // Extrai nome do arquivo da URL (último segmento antes de ?)
            const filename = (src.split('?')[0].split('/').pop() || 'imagem').slice(0, 120);
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        })
        .catch((err) => {
            console.error('[ConversationDrawer] download error:', err);
            toast.add({ severity: 'error', summary: 'Erro', detail: 'Falha ao baixar imagem.', life: 3500 });
        });
}

function injectDownloadButton(toolbar) {
    if (!toolbar || toolbar.querySelector('[data-download-btn]')) return;
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.setAttribute('aria-label', 'Baixar imagem');
    btn.setAttribute('data-download-btn', '1');
    btn.setAttribute('data-pc-group-section', 'action');
    // Herda a classe p-image-closeButton pra pegar o mesmo styling do toolbar
    btn.className = 'p-image-close-button';
    btn.innerHTML = '<span class="pi pi-download" style="font-size: 1rem;"></span>';
    btn.addEventListener('click', (e) => {
        e.stopPropagation();
        // Escopa o lookup ao mask específico deste botão (seguro se houver múltiplos previews)
        const mask = btn.closest('.p-image-mask');
        const img = mask?.querySelector('img.p-image-original, img')
            ?? document.querySelector('.p-image-original');
        triggerImageDownload(img?.src);
    });
    // Insere antes do close (último)
    const closeBtn = toolbar.querySelector('[aria-label*="lose" i]') || toolbar.lastElementChild;
    toolbar.insertBefore(btn, closeBtn);
}

onMounted(() => {
    _toolbarObserver = new MutationObserver((mutations) => {
        for (const m of mutations) {
            for (const node of m.addedNodes) {
                if (!(node instanceof HTMLElement)) continue;
                const toolbar = node.matches?.('.p-image-toolbar') ? node : node.querySelector?.('.p-image-toolbar');
                if (toolbar) injectDownloadButton(toolbar);
            }
        }
    });
    _toolbarObserver.observe(document.body, { childList: true, subtree: true });
});

onBeforeUnmount(() => {
    _toolbarObserver?.disconnect();
    _toolbarObserver = null;
});

// ── Compose ────────────────────────────────────────────────
async function sendMessage() {
    const text = composeText.value.trim();
    if (!text) return;
    const result = await store.sendMessage(text);
    if (result.ok) {
        composeText.value = '';
        toast.add({ severity: 'success', summary: 'Mensagem enviada', life: 2000 });
    } else {
        toast.add({ severity: 'error', summary: 'Falha ao enviar', detail: result.error, life: 5000 });
    }
}

function onComposeKeydown(e) {
    if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault();
        sendMessage();
    }
}

async function onMoveTo(newStatus) {
    try {
        await store.setKanbanStatus(newStatus);
        const label = KANBAN_COLUMNS.find(c => c.key === newStatus)?.label;
        toast.add({ severity: 'success', summary: 'Movido', detail: `Conversa movida para ${label}.`, life: 2000 });
    } catch (err) {
        toast.add({ severity: 'error', summary: 'Erro', detail: err?.message || 'Falha ao mover.', life: 4000 });
    }
}

// ── Templates ──────────────────────────────────────────────
function templateFriendlyLabel(key) {
    const map = {
        'session.lembrete': 'Lembrete de sessão (24h antes)',
        'session.lembrete_2h': 'Lembrete de sessão (2h antes)',
        'session.confirmacao': 'Confirmação de agendamento',
        'session.cancelamento': 'Sessão cancelada',
        'session.reagendamento': 'Sessão reagendada',
        'cobranca.pendente': 'Cobrança pendente',
        'sistema.boas_vindas': 'Boas-vindas ao paciente'
    };
    const stripped = key.replace('.whatsapp', '');
    const prefix = stripped.split('.').slice(0, 2).join('.');
    return map[prefix] || stripped;
}

async function applyTemplate(tpl) {
    const { text, missing } = await store.resolveTemplate(tpl);
    composeText.value = composeText.value ? composeText.value + '\n' + text : text;
    templatesPopover.value?.hide();
    nextTick(() => {
        const el = composeTextareaRef.value?.$el?.querySelector('textarea') ?? null;
        if (el?.focus) el.focus();
    });
    if (missing.length) {
        toast.add({
            severity: 'warn',
            summary: 'Variáveis sem valor',
            detail: `Não consegui preencher: ${missing.join(', ')}. Edita a mensagem antes de enviar.`,
            life: 5000
        });
    }
}

function openTemplatesPopover(ev) {
    if (!store.templatesLoaded) store.loadTemplates();
    templatesPopover.value?.toggle(ev);
}

// ── Emoji ──────────────────────────────────────────────────
const emojiList = [
    '😀','😃','😄','😁','😆','😅','🤣','😂','🙂','🙃','😉','😊',
    '😍','🥰','😘','😗','😙','😚','😋','😛','😜','🤪','😝','🤗',
    '🤔','🤨','😐','😑','😶','🙄','😏','😒','😔','😪','🤤','😴',
    '😎','🤓','🧐','🤯','😳','🥵','🥶','😱','😨','😰','😥','😓',
    '👍','👎','👌','✌️','🤞','🤟','🤘','👈','👉','👆','🖕','👇',
    '👋','🙌','👏','🤝','🙏','💪','🫶','❤️','🧡','💛','💚','💙',
    '💜','🖤','🤍','🤎','💔','❣️','💕','💞','💓','💗','💖','💘',
    '✨','⭐','🌟','💫','⚡','🔥','💯','✅','❌','⚠️','💬','💭'
];

function toggleEmojiPopover(ev) {
    emojiPopover.value?.toggle(ev);
}

function insertEmoji(emoji) {
    const el = composeTextareaRef.value?.$el?.querySelector('textarea') ?? null;
    if (el && typeof el.selectionStart === 'number') {
        const start = el.selectionStart;
        const end = el.selectionEnd;
        const before = composeText.value.slice(0, start);
        const after = composeText.value.slice(end);
        composeText.value = before + emoji + after;
        nextTick(() => {
            el.focus();
            const pos = start + emoji.length;
            el.setSelectionRange(pos, pos);
        });
    } else {
        composeText.value += emoji;
    }
}
</script>

<template>
    <!-- group="conversation-drawer" isola esse confirm das páginas (evita 2x modal). -->
    <ConfirmDialog group="conversation-drawer" />
    <Drawer v-model:visible="isOpen" position="right" class="!w-full md:!w-[520px]">
        <template #header>
            <div v-if="store.thread" class="flex items-center gap-3 min-w-0">
                <span class="cd-avatar">
                    {{ iniciaisChat(contactLabel()) }}
                </span>
                <div class="flex flex-col min-w-0">
                    <span class="font-semibold truncate text-[0.95rem]">{{ contactLabel() }}</span>
                    <span v-if="store.thread.contact_number" class="text-[0.72rem] text-[var(--text-color-secondary)] flex items-center gap-1.5">
                        <i :class="['pi', channelIcon(store.thread.channel), 'text-[0.65rem]']" />
                        <span class="font-mono">{{ formatPhoneShort(store.thread.contact_number) }}</span>
                    </span>
                </div>
            </div>
        </template>

        <div v-if="store.thread" class="flex flex-col gap-3 h-full">
            <!-- Ações: responder no WhatsApp Web + converter em paciente -->
            <div class="flex items-center gap-1.5 flex-wrap border-b border-[var(--surface-border)] pb-3">
                <a v-if="whatsappLink()" :href="whatsappLink()" target="_blank" rel="noopener">
                    <Button label="Abrir no WhatsApp Web" icon="pi pi-external-link" severity="secondary" outlined size="small" />
                </a>
                <template v-if="!store.thread.patient_id && store.thread.contact_number">
                    <Button
                        label="Novo paciente"
                        icon="pi pi-user-plus"
                        severity="primary"
                        size="small"
                        class="rounded-full"
                        v-tooltip.top="'Cadastra este número como novo paciente e vincula a conversa'"
                        @click="openConvertToPatient"
                    />
                    <Button
                        label="Vincular existente"
                        icon="pi pi-link"
                        severity="secondary"
                        outlined
                        size="small"
                        class="rounded-full"
                        v-tooltip.top="'Liga essa conversa a um paciente já cadastrado'"
                        @click="openLinkPatient"
                    />
                </template>
            </div>

            <!-- Cadastro rápido pré-preenchido com telefone da thread -->
            <ComponentCadastroRapido
                v-model="quickPatientDialog"
                title="Cadastrar novo paciente"
                :initial-data="{
                    nome_completo: store.thread.patient_name || '',
                    telefone: phoneForForm(store.thread.contact_number)
                }"
                @created="onPatientCreated"
            />

            <!-- Dialog: vincular a paciente existente -->
            <Dialog
                v-model:visible="linkPatientDialog"
                header="Vincular a paciente existente"
                modal
                :style="{ width: 'min(480px, 95vw)' }"
            >
                <div class="flex flex-col gap-3">
                    <div class="text-xs text-[var(--text-color-secondary)]">
                        Escolha ou busque um paciente pra vincular ao número
                        <strong class="font-mono">{{ formatPhoneShort(store.thread?.contact_number) }}</strong>.
                    </div>

                    <Select
                        v-model="linkPatientSelected"
                        :options="linkPatientOptions"
                        optionLabel="_label"
                        :filter="true"
                        filterPlaceholder="Buscar por nome, telefone ou email…"
                        :filterFields="['nome_completo', 'telefone', 'email_principal', '_label']"
                        placeholder="Selecione um paciente"
                        :loading="linkPatientLoading"
                        class="w-full"
                        :emptyFilterMessage="'Nenhum paciente encontrado'"
                        :emptyMessage="'Nenhum paciente cadastrado ainda'"
                        appendTo="body"
                    >
                        <template #value="slotProps">
                            <div v-if="slotProps.value" class="flex items-center gap-2">
                                <div class="w-7 h-7 rounded-full grid place-items-center bg-indigo-500/10 text-indigo-500 font-bold text-[0.65rem] shrink-0">
                                    {{ (slotProps.value.nome_completo || '?').slice(0, 2).toUpperCase() }}
                                </div>
                                <div class="flex-1 min-w-0 text-sm">
                                    <div class="font-semibold truncate">{{ slotProps.value.nome_completo }}</div>
                                    <div v-if="slotProps.value.telefone" class="text-[0.68rem] text-[var(--text-color-secondary)] font-mono">{{ formatPhoneShort(slotProps.value.telefone) }}</div>
                                </div>
                            </div>
                            <span v-else class="text-[var(--text-color-secondary)]">{{ slotProps.placeholder }}</span>
                        </template>

                        <template #option="slotProps">
                            <div class="flex items-center gap-2 w-full">
                                <div class="w-8 h-8 rounded-full grid place-items-center bg-indigo-500/10 text-indigo-500 font-bold text-xs shrink-0">
                                    {{ (slotProps.option.nome_completo || '?').slice(0, 2).toUpperCase() }}
                                </div>
                                <div class="flex-1 min-w-0">
                                    <div class="text-sm font-semibold truncate">{{ slotProps.option.nome_completo }}</div>
                                    <div class="text-[0.68rem] text-[var(--text-color-secondary)] flex items-center gap-1.5">
                                        <span v-if="slotProps.option.telefone" class="font-mono">{{ formatPhoneShort(slotProps.option.telefone) }}</span>
                                        <span v-if="slotProps.option.email_principal" class="truncate">· {{ slotProps.option.email_principal }}</span>
                                    </div>
                                </div>
                            </div>
                        </template>
                    </Select>
                </div>

                <template #footer>
                    <Button label="Cancelar" severity="secondary" text :disabled="linkingPatient" @click="linkPatientDialog = false" />
                    <Button
                        label="Vincular"
                        icon="pi pi-link"
                        :loading="linkingPatient"
                        :disabled="!linkPatientSelected"
                        @click="confirmLinkPatient"
                    />
                </template>
            </Dialog>

            <!-- Mover entre colunas Kanban -->
            <div class="flex items-center gap-1.5 flex-wrap">
                <span class="text-xs text-[var(--text-color-secondary)]">Mover pra:</span>
                <Button
                    v-for="col in KANBAN_COLUMNS"
                    :key="col.key"
                    :label="col.label"
                    :icon="col.icon"
                    size="small"
                    :severity="store.thread.kanban_status === col.key ? 'primary' : 'secondary'"
                    :outlined="store.thread.kanban_status !== col.key"
                    :disabled="store.thread.kanban_status === col.key"
                    @click="onMoveTo(col.key)"
                />
            </div>

            <!-- Tags da thread -->
            <div class="flex items-center gap-1.5 flex-wrap">
                <span class="text-xs text-[var(--text-color-secondary)] shrink-0">Tags:</span>
                <span
                    v-for="t in tagsApi.threadTags.value"
                    :key="t.id"
                    class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[0.7rem] font-semibold cursor-pointer hover:opacity-80 transition-opacity"
                    :style="{
                        background: t.color + '20',
                        color: t.color,
                        border: `1px solid ${t.color}40`
                    }"
                    @click="onToggleTag(t.id)"
                    v-tooltip.top="'Clique para remover'"
                >
                    <i v-if="t.icon" :class="t.icon" class="text-[0.65rem]" />
                    {{ t.name }}
                    <i class="pi pi-times text-[0.6rem] opacity-60" />
                </span>
                <Button
                    icon="pi pi-plus"
                    severity="secondary"
                    outlined
                    size="small"
                    class="h-6 w-6 rounded-full"
                    v-tooltip.top="'Adicionar tag'"
                    :loading="tagsApi.saving.value"
                    @click="openTagsPopover"
                />
            </div>

            <!-- Popover de seleção de tags -->
            <Popover ref="tagsPopover" class="!w-[260px]">
                <div class="flex flex-col gap-0.5">
                    <div class="px-2 pb-1 text-[0.65rem] font-bold uppercase text-[var(--text-color-secondary)] opacity-65">
                        Selecione tags
                    </div>
                    <div v-if="tagsApi.loading.value" class="text-xs text-center py-3 text-[var(--text-color-secondary)]">
                        <i class="pi pi-spin pi-spinner mr-1" /> Carregando…
                    </div>
                    <div v-else-if="!tagsApi.allTags.value.length" class="text-xs text-center py-3 italic text-[var(--text-color-secondary)]">
                        Nenhuma tag disponível.
                    </div>
                    <button
                        v-else
                        v-for="t in tagsApi.allTags.value"
                        :key="t.id"
                        class="flex items-center gap-2 px-2 py-1.5 rounded-md text-sm text-left bg-transparent border-0 cursor-pointer hover:bg-[var(--surface-hover)] transition-colors"
                        @click="onToggleTag(t.id)"
                    >
                        <span
                            class="inline-block w-3 h-3 rounded-full shrink-0"
                            :style="{ background: t.color }"
                        />
                        <i v-if="t.icon" :class="t.icon" class="text-xs opacity-70 shrink-0" />
                        <span class="flex-1 truncate">{{ t.name }}</span>
                        <i v-if="tagsApi.threadTagIds.value.has(t.id)" class="pi pi-check text-xs text-[var(--primary-color)] shrink-0" />
                    </button>
                </div>
            </Popover>

            <!-- Atribuição da conversa -->
            <div class="flex items-center gap-1.5 flex-wrap">
                <span class="text-xs text-[var(--text-color-secondary)] shrink-0">Atribuída a:</span>
                <Select
                    :modelValue="assignApi.assignment.value?.assigned_to || null"
                    :options="assignApi.members.value"
                    optionLabel="label"
                    optionValue="user_id"
                    placeholder="Ninguém"
                    filter
                    showClear
                    size="small"
                    class="!min-w-[220px]"
                    :loading="assignApi.loading.value || assignApi.saving.value"
                    @update:modelValue="onAssignChange"
                />
                <Button
                    v-if="currentUserId && assignApi.assignment.value?.assigned_to !== currentUserId"
                    label="Assumir"
                    icon="pi pi-user-plus"
                    size="small"
                    severity="secondary"
                    outlined
                    class="rounded-full"
                    :loading="assignApi.saving.value"
                    v-tooltip.top="'Atribuir essa conversa a mim'"
                    @click="assignToMe"
                />
                <span
                    v-if="assignApi.assignment.value?.assigned_to"
                    class="text-[0.68rem] text-[var(--text-color-secondary)] italic"
                >
                    desde {{ fmtNoteDate(assignApi.assignment.value.assigned_at) }}
                </span>
            </div>

            <!-- Notas internas -->
            <div class="border border-[var(--surface-border)] rounded-md bg-[var(--surface-ground)]">
                <button
                    class="w-full flex items-center gap-2 px-3 py-2 text-left bg-transparent border-0 cursor-pointer hover:bg-[var(--surface-hover)] rounded-md transition-colors"
                    @click="notesOpen = !notesOpen"
                >
                    <i class="pi pi-file-edit text-[var(--primary-color)]" />
                    <span class="text-sm font-semibold">Notas internas</span>
                    <Badge v-if="notesApi.count.value" :value="notesApi.count.value" severity="secondary" />
                    <span v-else class="text-xs text-[var(--text-color-secondary)] italic">(nenhuma)</span>
                    <i class="pi ml-auto text-xs" :class="notesOpen ? 'pi-chevron-up' : 'pi-chevron-down'" />
                </button>

                <div v-if="notesOpen" class="px-3 pb-3 flex flex-col gap-2">
                    <!-- Adicionar nota -->
                    <div class="flex gap-2 items-start">
                        <Textarea
                            v-model="newNoteText"
                            rows="2"
                            autoResize
                            placeholder="Escreva uma nota interna (só a equipe vê)…"
                            class="flex-1 text-sm"
                            :maxlength="4000"
                            :disabled="notesApi.saving.value"
                            @keydown.ctrl.enter="addNote"
                            @keydown.meta.enter="addNote"
                        />
                        <Button
                            icon="pi pi-plus"
                            severity="primary"
                            v-tooltip.left="'Adicionar (Ctrl+Enter)'"
                            :loading="notesApi.saving.value"
                            :disabled="!newNoteText.trim()"
                            @click="addNote"
                        />
                    </div>

                    <!-- Lista -->
                    <div v-if="notesApi.loading.value" class="text-xs text-[var(--text-color-secondary)] text-center py-2">
                        <i class="pi pi-spin pi-spinner mr-1" /> Carregando notas…
                    </div>
                    <div v-else-if="!notesApi.notes.value.length" class="text-xs text-[var(--text-color-secondary)] text-center py-2 italic">
                        Nenhuma nota ainda. Use o campo acima pra registrar observações da equipe.
                    </div>
                    <div v-else class="flex flex-col gap-1.5 max-h-[40vh] overflow-y-auto pr-1">
                        <div
                            v-for="n in notesApi.notes.value"
                            :key="n.id"
                            class="rounded-md border border-[var(--surface-border)] p-2 bg-[var(--surface-card)]"
                        >
                            <!-- Modo edição -->
                            <template v-if="editingNoteId === n.id">
                                <Textarea
                                    v-model="editingText"
                                    rows="3"
                                    autoResize
                                    class="w-full text-sm mb-1.5"
                                    :maxlength="4000"
                                    :disabled="notesApi.saving.value"
                                />
                                <div class="flex gap-1 justify-end">
                                    <Button label="Cancelar" size="small" severity="secondary" text @click="cancelEditNote" />
                                    <Button label="Salvar" size="small" :loading="notesApi.saving.value" :disabled="!editingText.trim()" @click="saveEditNote(n.id)" />
                                </div>
                            </template>

                            <!-- Modo leitura -->
                            <template v-else>
                                <div class="text-sm whitespace-pre-wrap break-words text-[var(--text-color)]">{{ n.body }}</div>
                                <div class="flex items-center justify-between mt-1.5 text-[0.7rem] text-[var(--text-color-secondary)]">
                                    <span class="truncate">
                                        <i class="pi pi-user text-[0.6rem] mr-0.5 opacity-60" />
                                        {{ n._author_name || 'Usuário' }}
                                        <span class="mx-1 opacity-50">·</span>
                                        {{ fmtNoteDate(n.created_at) }}
                                        <span v-if="n.updated_at && n.updated_at !== n.created_at" class="ml-1 italic opacity-70">(editada)</span>
                                    </span>
                                    <div v-if="n.created_by === currentUserId" class="flex gap-0.5 shrink-0">
                                        <button
                                            class="w-6 h-6 rounded-full border-none bg-transparent text-[var(--text-color-secondary)] grid place-items-center cursor-pointer hover:bg-[var(--surface-hover)]"
                                            v-tooltip.top="'Editar'"
                                            @click="startEditNote(n)"
                                        >
                                            <i class="pi pi-pencil text-[0.7rem]" />
                                        </button>
                                        <button
                                            class="w-6 h-6 rounded-full border-none bg-transparent text-[var(--text-color-secondary)] grid place-items-center cursor-pointer hover:bg-red-500/10 hover:text-red-500"
                                            v-tooltip.top="'Remover'"
                                            @click="confirmDeleteNote(n.id)"
                                        >
                                            <i class="pi pi-trash text-[0.7rem]" />
                                        </button>
                                    </div>
                                </div>
                            </template>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Mensagens — container com bg WhatsApp-like -->
            <div ref="messagesContainerRef" class="cd-msgs flex-1 overflow-y-auto flex flex-col gap-1.5 p-3">
                <div v-if="store.loading" class="text-xs text-[var(--text-color-secondary)] text-center py-6">
                    <i class="pi pi-spin pi-spinner mr-2" />Carregando mensagens...
                </div>
                <div v-else-if="!store.messages.length" class="text-xs text-[var(--text-color-secondary)] text-center py-6 italic">
                    Nenhuma mensagem ainda. Envie a primeira abaixo.
                </div>

                <div
                    v-for="m in store.messages"
                    :key="m.id"
                    class="cd-bubble-wrap"
                    :class="m.direction === 'inbound' ? 'cd-bubble-wrap--in' : 'cd-bubble-wrap--out'"
                >
                    <div
                        class="cd-bubble"
                        :class="m.direction === 'inbound' ? 'cd-bubble--in' : 'cd-bubble--out'"
                    >
                        <template v-if="m.media_url">
                            <!-- Loading enquanto resolve signed URL -->
                            <div v-if="!mediaUrls[m.id]" class="flex items-center gap-2 text-xs text-[var(--text-color-secondary)] py-2">
                                <i class="pi pi-spin pi-spinner" /> carregando mídia…
                            </div>
                            <template v-else>
                                <Image
                                    v-if="isImage(m.media_mime)"
                                    :src="mediaUrls[m.id]"
                                    :preview="true"
                                    alt="imagem"
                                    imageClass="max-w-full rounded-md cursor-zoom-in"
                                    class="mb-1 block cd-bubble__media"
                                />
                                <audio
                                    v-else-if="isAudio(m.media_mime)"
                                    :src="mediaUrls[m.id]"
                                    controls
                                    preload="metadata"
                                    class="block w-full min-w-[260px] max-w-full mb-1"
                                />
                                <video
                                    v-else-if="isVideo(m.media_mime)"
                                    :src="mediaUrls[m.id]"
                                    controls
                                    class="max-w-full rounded-md mb-1 cd-bubble__media"
                                />
                                <a
                                    v-else
                                    :href="mediaUrls[m.id]"
                                    target="_blank"
                                    rel="noopener"
                                    class="inline-flex items-center gap-2 text-xs underline text-[var(--primary-color)] mb-1"
                                >
                                    <i class="pi pi-paperclip" />
                                    Baixar anexo ({{ m.media_mime || 'arquivo' }})
                                </a>
                            </template>
                        </template>
                        <div v-if="m.body" class="cd-bubble__body">{{ m.body }}</div>
                        <!-- Time + status overlay no canto inferior direito (estilo WhatsApp) -->
                        <div class="cd-bubble__meta">
                            <span>{{ fmtTimeOnly(m.created_at) }}</span>
                            <span v-if="m.direction === 'outbound'" class="cd-bubble__status">
                                <i v-if="m.delivery_status === 'read'" class="pi pi-check-double cd-bubble__status--read" v-tooltip.top="'Lida'" />
                                <i v-else-if="m.delivery_status === 'delivered'" class="pi pi-check-double" v-tooltip.top="'Entregue'" />
                                <i v-else-if="m.delivery_status === 'sent'" class="pi pi-check" v-tooltip.top="'Enviada'" />
                                <i v-else-if="m.delivery_status === 'failed'" class="pi pi-exclamation-circle text-red-500" v-tooltip.top="'Falhou'" />
                            </span>
                        </div>
                    </div>
                    <span v-if="m.direction === 'inbound' && !m.patient_id" class="cd-bubble__unlinked">não vinculado</span>
                </div>
            </div>

            <!-- Banner de erro de envio (persistente até user enviar com sucesso ou dispensar) -->
            <div
                v-if="store.lastSendError"
                class="flex items-start gap-2.5 mt-2 px-3 py-2.5 rounded-lg border border-amber-300/60 bg-amber-50 text-amber-900 dark:border-amber-500/40 dark:bg-amber-500/10 dark:text-amber-100"
            >
                <i class="pi pi-exclamation-triangle text-amber-600 dark:text-amber-300 mt-0.5 shrink-0" />
                <div class="flex-1 min-w-0">
                    <div class="text-sm font-medium leading-snug">{{ store.lastSendError.message }}</div>
                    <div v-if="store.lastSendError.hint" class="text-xs opacity-85 mt-0.5 leading-snug">
                        {{ store.lastSendError.hint }}
                    </div>
                    <div v-if="store.lastSendError.action || store.lastSendError.secondaryAction" class="flex flex-wrap gap-3 mt-1.5">
                        <RouterLink
                            v-if="store.lastSendError.action"
                            :to="store.lastSendError.action.url"
                            class="inline-flex items-center gap-1 text-xs font-semibold underline hover:no-underline"
                            @click="store.dismissSendError()"
                        >
                            {{ store.lastSendError.action.label }} <i class="pi pi-arrow-right text-[0.6rem]" />
                        </RouterLink>
                        <RouterLink
                            v-if="store.lastSendError.secondaryAction"
                            :to="store.lastSendError.secondaryAction.url"
                            class="inline-flex items-center gap-1 text-xs font-medium underline hover:no-underline opacity-90"
                            @click="store.dismissSendError()"
                        >
                            {{ store.lastSendError.secondaryAction.label }} <i class="pi pi-arrow-right text-[0.6rem]" />
                        </RouterLink>
                    </div>
                </div>
                <button
                    class="shrink-0 w-6 h-6 grid place-items-center rounded hover:bg-amber-100 dark:hover:bg-amber-500/20 transition-colors"
                    title="Dispensar"
                    @click="store.dismissSendError()"
                >
                    <i class="pi pi-times text-[0.7rem]" />
                </button>
            </div>

            <!-- Compose — barra estilo WhatsApp (input pill + send circular) -->
            <div v-if="store.thread.channel === 'whatsapp' && store.thread.contact_number" class="cd-compose">
                <div class="cd-compose__row">
                    <button
                        class="cd-compose__icon-btn"
                        v-tooltip.top="'Emoji'"
                        @click="toggleEmojiPopover"
                    >
                        <i class="pi pi-face-smile" />
                    </button>
                    <button
                        class="cd-compose__icon-btn"
                        v-tooltip.top="'Templates'"
                        @click="openTemplatesPopover"
                    >
                        <i class="pi pi-bookmark" />
                    </button>
                    <Textarea
                        ref="composeTextareaRef"
                        v-model="composeText"
                        autoResize
                        rows="1"
                        placeholder="Digite uma mensagem"
                        class="cd-compose__input flex-1"
                        :disabled="store.sending"
                        :maxlength="4000"
                        @keydown="onComposeKeydown"
                    />
                    <button
                        class="cd-compose__send"
                        :class="{ 'is-disabled': !composeText.trim() || store.sending }"
                        :disabled="!composeText.trim() || store.sending"
                        v-tooltip.top="'Enviar (Enter)'"
                        @click="sendMessage"
                    >
                        <i v-if="store.sending" class="pi pi-spin pi-spinner" />
                        <i v-else class="pi pi-send" />
                    </button>
                </div>
                <div class="cd-compose__hint">
                    <span>Enter envia · Shift+Enter quebra linha</span>
                    <span class="ml-auto">{{ composeText.length }}/4000</span>
                </div>
            </div>
            <div v-else class="text-[0.7rem] text-[var(--text-color-secondary)] italic text-center py-2 border-t border-[var(--surface-border)]">
                Envio direto indisponível (canal: {{ store.thread.channel }}).
            </div>
        </div>

        <!-- Popover: Templates -->
        <Popover ref="templatesPopover" :pt="{ content: { class: '!p-0' } }">
            <div class="w-[320px] max-h-[400px] overflow-y-auto">
                <div class="px-3 py-2 border-b border-[var(--surface-border)] text-xs font-semibold text-[var(--text-color-secondary)] uppercase tracking-wide">
                    Templates WhatsApp
                </div>
                <div v-if="store.templatesLoading" class="p-4 text-xs text-center text-[var(--text-color-secondary)]">
                    <i class="pi pi-spin pi-spinner mr-1" /> Carregando...
                </div>
                <div v-else-if="!store.templates.length" class="p-4 text-xs text-center text-[var(--text-color-secondary)] italic">
                    Nenhum template disponível.
                </div>
                <button
                    v-for="tpl in store.templates"
                    :key="tpl.id"
                    class="w-full text-left px-3 py-2 border-none bg-transparent cursor-pointer hover:bg-[var(--surface-hover)] border-b border-[var(--surface-border)] last:border-b-0"
                    @click="applyTemplate(tpl)"
                >
                    <div class="text-xs font-semibold text-[var(--text-color)] truncate">{{ templateFriendlyLabel(tpl.key) }}</div>
                    <div class="text-[0.7rem] text-[var(--text-color-secondary)] line-clamp-2 mt-0.5">{{ tpl.body_text }}</div>
                </button>
            </div>
        </Popover>

        <!-- Popover: Emoji picker -->
        <Popover ref="emojiPopover" :pt="{ content: { class: '!p-2' } }">
            <div class="w-[280px] max-h-[280px] overflow-y-auto grid grid-cols-8 gap-1">
                <button
                    v-for="e in emojiList"
                    :key="e"
                    class="w-8 h-8 rounded hover:bg-[var(--surface-hover)] border-none bg-transparent cursor-pointer text-lg"
                    @click="insertEmoji(e)"
                >{{ e }}</button>
            </div>
        </Popover>
    </Drawer>
</template>

<style scoped>
/* ─── Avatar do header (iniciais sobre primary) ─── */
.cd-avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--p-primary-color);
    color: var(--p-primary-contrast-color, white);
    font-weight: 700;
    font-size: 0.85rem;
    flex-shrink: 0;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}

/* ─── Container de mensagens (bg estilo "papel de parede" WhatsApp) ─── */
/* Light: bege esverdeado clássico do WA. Dark: cinza profundo tipo
   wallpaper de modo escuro. Adapta via CSS variable `--p-content-background`
   pra harmonizar com o tema do app. */
/* Background do chat estilo WhatsApp.
   Light: cor bege classica (#efeae2) com a imagem doodle por cima usando
   mix-blend multiply pra integrar.
   Dark: cor #0b141a (mesma do WhatsApp Web dark) + camada escura translucida
   por cima da imagem pra dimming. */
.cd-msgs {
    background-color: #efeae2;
    background-image: url('../../assets/whatsapp-bg.jpg');
    background-size: 380px auto;
    background-repeat: repeat;
    background-blend-mode: multiply;
    border-radius: 8px;
    margin: 0 -2px;
}
:where(.p-dark, html.dark, [data-theme="dark"]) .cd-msgs,
.cd-msgs:where(.p-dark *, html.dark *, [data-theme="dark"] *) {
    background-color: #0b141a;
    background-image:
        linear-gradient(rgba(11, 20, 26, 0.78), rgba(11, 20, 26, 0.78)),
        url('../../assets/whatsapp-bg.jpg');
    background-blend-mode: normal;
}

/* ─── Bolha (wrapper + content + meta) ─── */
.cd-bubble-wrap {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-width: 80%;
}
.cd-bubble-wrap--in { align-self: flex-start; }
.cd-bubble-wrap--out { align-self: flex-end; align-items: flex-end; }

.cd-bubble {
    position: relative;
    padding: 6px 10px 18px 10px;
    border-radius: 8px;
    font-size: 0.88rem;
    line-height: 1.42;
    word-wrap: break-word;
    overflow-wrap: break-word;
    white-space: pre-wrap;
    box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.13);
    min-width: 80px;
}
/* Inbound: surface-card adapta light/dark; canto top-left "achatado" vira o tail */
.cd-bubble--in {
    background: var(--p-surface-0, #ffffff);
    color: var(--p-text-color);
    border-top-left-radius: 0;
}
:global(.p-dark) .cd-bubble--in,
:global(html.dark) .cd-bubble--in,
:global([data-theme="dark"]) .cd-bubble--in,
.cd-bubble--in:where(.p-dark *, html.dark *, [data-theme="dark"] *) {
    background: #202c33;
    color: rgb(233, 237, 239);
}

/* Outbound: verde claro WA (light) / verde escuro WA (dark) */
.cd-bubble--out {
    background: #d9fdd3;
    color: rgb(17, 27, 33);
    border-top-right-radius: 0;
}
:global(.p-dark) .cd-bubble--out,
:global(html.dark) .cd-bubble--out,
:global([data-theme="dark"]) .cd-bubble--out,
.cd-bubble--out:where(.p-dark *, html.dark *, [data-theme="dark"] *) {
    background: #005c4b;
    color: rgb(233, 237, 239);
}

.cd-bubble__body {
    margin-bottom: 2px;
}
.cd-bubble__media {
    border-radius: 6px;
    margin: -2px -4px 6px -4px;
    max-width: calc(100% + 8px);
}

/* Meta (HH:MM + status checks) overlay no canto inferior direito */
.cd-bubble__meta {
    position: absolute;
    right: 8px;
    bottom: 4px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.62rem;
    font-weight: 500;
    line-height: 1;
    color: rgba(0, 0, 0, 0.45);
    pointer-events: auto;
    user-select: none;
}
.cd-bubble--in .cd-bubble__meta { color: rgba(0, 0, 0, 0.45); }
.cd-bubble--out .cd-bubble__meta { color: rgba(0, 0, 0, 0.55); }
:global(.p-dark) .cd-bubble--in .cd-bubble__meta,
:global(html.dark) .cd-bubble--in .cd-bubble__meta,
:global([data-theme="dark"]) .cd-bubble--in .cd-bubble__meta,
.cd-bubble--in:where(.p-dark *, html.dark *, [data-theme="dark"] *) .cd-bubble__meta {
    color: rgba(255, 255, 255, 0.55);
}
:global(.p-dark) .cd-bubble--out .cd-bubble__meta,
:global(html.dark) .cd-bubble--out .cd-bubble__meta,
:global([data-theme="dark"]) .cd-bubble--out .cd-bubble__meta,
.cd-bubble--out:where(.p-dark *, html.dark *, [data-theme="dark"] *) .cd-bubble__meta {
    color: rgba(233, 237, 239, 0.6);
}

.cd-bubble__status > i {
    font-size: 0.78rem;
}
.cd-bubble__status--read {
    color: rgb(83, 189, 235) !important; /* azul WA quando lido */
}

.cd-bubble__unlinked {
    font-size: 0.62rem;
    color: var(--p-text-muted-color, var(--text-color-secondary));
    font-style: italic;
    padding-left: 2px;
}

/* ─── Compose bar estilo WhatsApp ─── */
.cd-compose {
    border-top: 1px solid var(--p-content-border-color, var(--surface-border));
    padding: 8px 4px 6px;
    background: color-mix(in srgb, var(--p-content-background) 80%, transparent);
}
.cd-compose__row {
    display: flex;
    align-items: flex-end;
    gap: 6px;
}
.cd-compose__icon-btn {
    width: 36px;
    height: 36px;
    display: grid;
    place-items: center;
    background: transparent;
    border: none;
    color: var(--p-text-muted-color);
    border-radius: 50%;
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color 140ms ease, color 140ms ease;
}
.cd-compose__icon-btn:hover {
    background: var(--p-content-hover-background, color-mix(in srgb, var(--p-text-color) 8%, transparent));
    color: var(--p-text-color);
}
.cd-compose__icon-btn > i { font-size: 1rem; }

.cd-compose__input :deep(textarea),
.cd-compose__input.p-textarea {
    border-radius: 22px !important;
    background: var(--p-surface-0) !important;
    border: 1px solid var(--p-content-border-color) !important;
    padding: 9px 16px !important;
    font-size: 0.88rem !important;
    line-height: 1.4 !important;
    resize: none !important;
    min-height: 40px;
    max-height: 120px;
    transition: border-color 140ms ease, box-shadow 140ms ease;
}
.cd-compose__input :deep(textarea:focus) {
    border-color: var(--p-primary-color) !important;
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--p-primary-color) 22%, transparent) !important;
}

.cd-compose__send {
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    background: #00a884; /* verde send do WA */
    border: none;
    color: white;
    border-radius: 50%;
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color 140ms ease, transform 140ms ease, opacity 140ms ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.cd-compose__send:hover:not(.is-disabled) {
    background: #06cf9c;
    transform: translateY(-1px);
}
.cd-compose__send.is-disabled,
.cd-compose__send:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background: var(--p-content-hover-background);
    color: var(--p-text-muted-color);
}
.cd-compose__send > i { font-size: 1rem; }

.cd-compose__hint {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 0;
    font-size: 0.62rem;
    color: var(--p-text-muted-color);
    opacity: 0.7;
}
</style>
