<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/views/pages/saas/SaasDocsPage.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<!-- SaaS admin: CRUD de documentação dinâmica exibida nas páginas do sistema -->
<script setup>
import { ref, computed, onMounted } from 'vue';
import { supabase } from '@/lib/supabase/client';
import { useToast } from 'primevue/usetoast';
import { useConfirm } from 'primevue/useconfirm';
import Editor from 'primevue/editor';
import { FilterMatchMode } from '@primevue/core/api';
import { PAGE_OPTIONS } from '@/utils/menuPageOptions';
import { invalidateAjudaCache } from '@/composables/useAjuda';
import { useDocsAdmin } from '@/composables/useDocsAdmin';
import { useDocsHealth } from '@/composables/useDocsHealth';

const toast = useToast();
const confirm = useConfirm();
const { consumePendingEdit } = useDocsAdmin();
const { setDocs, saudeDoc, pctNegativo, totalDocs, docsAtencao, docsOk, docsSemDados, countAtencao, docMaisUtil, sortBySaude } = useDocsHealth();

// ── Estado ────────────────────────────────────────────────────
const loading = ref(false);
const docs = ref([]);

// ── Dialog ────────────────────────────────────────────────────
const dlgOpen = ref(false);
const saving = ref(false);
const editId = ref(null);
const activeTab = ref(0); // 0 = Conteúdo, 1 = FAQ, 2 = Mídias, 3 = Configurações
const form = ref(emptyForm());

function emptyForm() {
    return {
        titulo: '',
        conteudo: '',
        categoria: '',
        exibir_no_faq: false,
        tipo_acesso: 'usuario',
        pagina_path: null,
        medias: [],
        docs_relacionados: [],
        ativo: true,
        ordem: 0,
        _custom_path: '',
        _faq_itens: []
    };
}

const tipoAcessoOptions = [
    { label: 'Usuários (todos)', value: 'usuario' },
    { label: 'Admin (clinic_admin, tenant_admin, saas)', value: 'admin' }
];

// ── Categorias dinâmicas ──────────────────────────────────────
const categorias = computed(() => {
    const set = new Set(docs.value.map((d) => d.categoria).filter(Boolean));
    return [...set].sort();
});

// ── Opções de página ──────────────────────────────────────────
const pageSelectOptions = computed(() => [...PAGE_OPTIONS, { label: '— Caminho personalizado —', path: '__custom__' }]);

const isCustomPath = computed(() => form.value.pagina_path === '__custom__');

// Contagem de docs por path (excluindo o próprio doc em edição)
const docsCountByPath = computed(() => {
    const map = new Map();
    for (const d of docs.value) {
        if (d.id === editId.value) continue;
        if (!d.pagina_path) continue;
        map.set(d.pagina_path, (map.get(d.pagina_path) || 0) + 1);
    }
    return map;
});

const resolvedPath = computed(() => {
    if (isCustomPath.value) return form.value._custom_path.trim();
    return form.value.pagina_path || '';
});

// ── Docs relacionados (MultiSelect) ───────────────────────────
const docsRelOptions = computed(() =>
    docs.value
        .filter((d) => d.id !== editId.value)
        .map((d) => ({
            label: `${d.titulo}  ·  ${d.pagina_path}`,
            value: d.id
        }))
);

const formValid = computed(() => !!form.value.titulo.trim() && !!resolvedPath.value);

// ── Dialog abrir ──────────────────────────────────────────────
async function abrirDialog(doc = null) {
    activeTab.value = 0;
    if (doc) {
        editId.value = doc.id;
        const isCustom = !PAGE_OPTIONS.find((p) => p.path === doc.pagina_path);
        form.value = {
            titulo: doc.titulo || '',
            conteudo: doc.conteudo || '',
            categoria: doc.categoria || '',
            exibir_no_faq: doc.exibir_no_faq ?? false,
            tipo_acesso: doc.tipo_acesso || 'usuario',
            pagina_path: isCustom ? '__custom__' : doc.pagina_path,
            medias: Array.isArray(doc.medias) ? JSON.parse(JSON.stringify(doc.medias)) : [],
            docs_relacionados: Array.isArray(doc.docs_relacionados) ? [...doc.docs_relacionados] : [],
            ativo: doc.ativo ?? true,
            ordem: doc.ordem ?? 0,
            _custom_path: isCustom ? doc.pagina_path : '',
            _faq_itens: []
        };
        // Carrega FAQ itens existentes
        await carregarFaqItens(doc.id);
    } else {
        editId.value = null;
        form.value = emptyForm();
    }
    dlgOpen.value = true;
}

// ── FAQ Itens ─────────────────────────────────────────────────
const faqLoading = ref(false);

async function carregarFaqItens(docId) {
    faqLoading.value = true;
    try {
        const { data, error } = await supabase.from('saas_faq_itens').select('id, pergunta, resposta, ordem, ativo').eq('doc_id', docId).order('ordem');
        if (error) throw error;
        form.value._faq_itens = (data || []).map((item) => ({
            ...item,
            _dirty: false, // marcador de alteração local
            _novo: false
        }));
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao carregar FAQ', detail: e?.message, life: 3000 });
    } finally {
        faqLoading.value = false;
    }
}

function addFaqItem() {
    form.value._faq_itens.push({
        id: null,
        pergunta: '',
        resposta: '',
        ordem: form.value._faq_itens.length,
        ativo: true,
        _dirty: true,
        _novo: true
    });
}

function removeFaqItem(idx) {
    form.value._faq_itens.splice(idx, 1);
}

// Salva os itens FAQ após salvar o doc
async function salvarFaqItens(docId) {
    const itens = form.value._faq_itens;

    // Identifica itens para deletar (que existiam mas foram removidos)
    // — isso é tratado pelo splice + controle de _novo

    // Upsert dos que existem na lista
    for (let i = 0; i < itens.length; i++) {
        const item = itens[i];
        if (!item.pergunta.trim()) continue;

        const payload = {
            doc_id: docId,
            pergunta: item.pergunta.trim(),
            resposta: item.resposta || '',
            ordem: i,
            ativo: item.ativo ?? true,
            updated_at: new Date().toISOString()
        };

        if (item._novo || !item.id) {
            const { data, error } = await supabase.from('saas_faq_itens').insert(payload).select('id').single();
            if (error) throw error;
            itens[i].id = data.id;
            itens[i]._novo = false;
        } else {
            const { error } = await supabase.from('saas_faq_itens').update(payload).eq('id', item.id);
            if (error) throw error;
        }
        itens[i]._dirty = false;
    }

    // Remove do banco itens que foram deletados da lista
    // (busca ids que existiam e não estão mais na lista)
    if (editId.value) {
        const idsAtuais = itens.map((i) => i.id).filter(Boolean);
        const { data: existentes } = await supabase.from('saas_faq_itens').select('id').eq('doc_id', docId);
        const existentesIds = (existentes || []).map((e) => e.id);
        const paraExcluir = existentesIds.filter((id) => !idsAtuais.includes(id));
        if (paraExcluir.length) {
            await supabase.from('saas_faq_itens').delete().in('id', paraExcluir);
        }
    }
}

// ── Mídias ────────────────────────────────────────────────────
function addMedia() {
    form.value.medias.push({ tipo: 'imagem', url: '' });
}
function removeMedia(idx) {
    form.value.medias.splice(idx, 1);
}

const uploadingIdx = ref(new Set());
const fileInputRefs = ref({});

function triggerUpload(idx) {
    fileInputRefs.value[idx]?.click();
}

async function uploadImagem(idx, event) {
    const file = event.target.files?.[0];
    if (!file) return;
    event.target.value = '';
    const ext = file.name.split('.').pop();
    const nome = `${crypto.randomUUID()}.${ext}`;
    const path = `doc-images/${nome}`;
    uploadingIdx.value = new Set([...uploadingIdx.value, idx]);
    try {
        const { error: upErr } = await supabase.storage.from('saas-docs').upload(path, file, { upsert: false, contentType: file.type });
        if (upErr) throw upErr;
        const { data } = supabase.storage.from('saas-docs').getPublicUrl(path);
        form.value.medias[idx].url = data.publicUrl;
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro no upload', detail: e?.message, life: 4000 });
    } finally {
        const next = new Set(uploadingIdx.value);
        next.delete(idx);
        uploadingIdx.value = next;
    }
}

// ── Salvar ────────────────────────────────────────────────────
async function salvar() {
    if (!formValid.value) return;
    saving.value = true;
    try {
        const payload = {
            titulo: form.value.titulo.trim(),
            conteudo: form.value.conteudo.trim(),
            categoria: form.value.categoria.trim() || null,
            exibir_no_faq: form.value.exibir_no_faq,
            tipo_acesso: form.value.tipo_acesso,
            pagina_path: resolvedPath.value,
            medias: form.value.medias.filter((m) => m.url.trim()),
            docs_relacionados: form.value.docs_relacionados,
            ativo: form.value.ativo,
            ordem: Number(form.value.ordem) || 0,
            updated_at: new Date().toISOString()
        };

        let docId = editId.value;

        if (editId.value) {
            const { error } = await supabase.from('saas_docs').update(payload).eq('id', editId.value);
            if (error) throw error;
            const idx = docs.value.findIndex((d) => d.id === editId.value);
            if (idx >= 0) docs.value[idx] = { ...docs.value[idx], ...payload, id: editId.value };
            toast.add({ severity: 'success', summary: 'Documento atualizado', life: 1800 });
        } else {
            const { data, error } = await supabase.from('saas_docs').insert(payload).select().single();
            if (error) throw error;
            docId = data.id;
            docs.value = [data, ...docs.value];
            toast.add({ severity: 'success', summary: 'Documento criado', life: 1800 });
        }

        // Salva itens FAQ
        await salvarFaqItens(docId);

        invalidateAjudaCache(resolvedPath.value);
        dlgOpen.value = false;
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message, life: 3500 });
    } finally {
        saving.value = false;
    }
}

// ── Excluir ───────────────────────────────────────────────────
function excluir(doc) {
    confirm.require({
        header: 'Excluir documento',
        message: `Tem certeza que deseja excluir "${doc.titulo}"? Esta ação não pode ser desfeita.`,
        icon: 'pi pi-exclamation-triangle',
        acceptLabel: 'Excluir',
        rejectLabel: 'Cancelar',
        acceptClass: 'p-button-danger',
        accept: async () => {
            try {
                const { error } = await supabase.from('saas_docs').delete().eq('id', doc.id);
                if (error) throw error;
                docs.value = docs.value.filter((d) => d.id !== doc.id);
                invalidateAjudaCache(doc.pagina_path);
                toast.add({ severity: 'success', summary: 'Documento removido', life: 1800 });
            } catch (e) {
                toast.add({ severity: 'error', summary: 'Erro ao excluir', detail: e?.message, life: 3000 });
            }
        }
    });
}

// ── Load ──────────────────────────────────────────────────────
async function load() {
    loading.value = true;
    try {
        const { data, error } = await supabase.from('saas_docs').select('*').order('pagina_path').order('ordem');
        if (error) throw error;
        docs.value = data || [];
        setDocs(docs.value);
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro', detail: e?.message, life: 3500 });
    } finally {
        loading.value = false;
    }
}

// ── Docs ordenados por saúde (problemáticos primeiro) ────────
const filtroAtencao = ref(false); // toggle para mostrar só problemáticos

const docsFiltrados = computed(() => {
    let lista = docs.value;
    if (filtroAtencao.value) lista = lista.filter((d) => saudeDoc(d) === 'atencao');
    return sortBySaude(lista);
});

onMounted(async () => {
    await load();
    // Verifica se veio da página de FAQ com um doc para editar
    const pendingId = consumePendingEdit();
    if (pendingId) {
        const doc = docs.value.find((d) => d.id === pendingId);
        if (doc) abrirDialog(doc);
    }
});

// ── Busca / Filtros ───────────────────────────────────────────
const filters = ref({
    global: { value: null, matchMode: FilterMatchMode.CONTAINS }
});

// ── Formatação de datas ───────────────────────────────────────
function fmtDate(iso) {
    if (!iso) return '—';
    return new Date(iso).toLocaleString('pt-BR', {
        day: '2-digit',
        month: '2-digit',
        year: 'numeric',
        hour: '2-digit',
        minute: '2-digit'
    });
}

// ── Preview ───────────────────────────────────────────────────
const previewDoc = ref(null);
const previewOpen = ref(false);
const previewFaqItens = ref([]);

async function abrirPreview(doc) {
    previewDoc.value = doc;
    previewOpen.value = true;
    // Carrega itens FAQ para o preview
    const { data } = await supabase.from('saas_faq_itens').select('id, pergunta, resposta, ordem').eq('doc_id', doc.id).eq('ativo', true).order('ordem');
    previewFaqItens.value = data || [];
}

const previewRelated = computed(() => {
    const ids = previewDoc.value?.docs_relacionados || [];
    return docs.value.filter((d) => ids.includes(d.id));
});

const previewFaqAbertos = ref({});
function togglePreviewFaq(id) {
    previewFaqAbertos.value[id] = !previewFaqAbertos.value[id];
}

// ── Dialog de Prompt ────────────────────────────────────────────
const promptDlgOpen = ref(false);

// ── Importar JSON ─────────────────────────────────────────────
const jsonFileInputRef = ref(null);

function copiarPrompt() {
    const pre = document.querySelector('.prompt-pre');
    if (!pre) return;
    navigator.clipboard.writeText(pre.textContent.trim()).then(() => {
        toast.add({ severity: 'success', summary: 'Prompt copiado!', detail: 'Cole no Claude e anexe o arquivo .vue', life: 2500 });
    });
}

function triggerJsonImport() {
    jsonFileInputRef.value?.click();
}

async function onJsonFileChange(event) {
    const file = event.target.files?.[0];
    if (!file) return;
    event.target.value = '';

    try {
        const text = await file.text();
        const json = JSON.parse(text);

        // Valida campos mínimos
        if (!json.titulo && !json.conteudo) {
            toast.add({ severity: 'warn', summary: 'JSON inválido', detail: 'O arquivo não parece ser uma documentação válida.', life: 3500 });
            return;
        }

        // Detecta se pagina_path é custom (não existe em PAGE_OPTIONS)
        const isCustom = json.pagina_path && !PAGE_OPTIONS.find((p) => p.path === json.pagina_path);

        // Popula form (mesmo padrão do abrirDialog)
        editId.value = null;
        form.value = {
            titulo: json.titulo || '',
            conteudo: json.conteudo || '',
            categoria: json.categoria || '',
            exibir_no_faq: json.exibir_no_faq ?? false,
            tipo_acesso: json.tipo_acesso || 'usuario',
            pagina_path: isCustom ? '__custom__' : json.pagina_path || null,
            medias: Array.isArray(json.medias) ? JSON.parse(JSON.stringify(json.medias)) : [],
            docs_relacionados: Array.isArray(json.docs_relacionados) ? [...json.docs_relacionados] : [],
            ativo: json.ativo ?? true,
            ordem: json.ordem ?? 0,
            _custom_path: isCustom ? json.pagina_path : '',
            _faq_itens: Array.isArray(json._faq_itens)
                ? json._faq_itens.map((item, i) => ({
                      id: null,
                      pergunta: item.pergunta || '',
                      resposta: item.resposta || '',
                      ordem: item.ordem ?? i,
                      ativo: item.ativo ?? true,
                      _dirty: true,
                      _novo: true
                  }))
                : []
        };

        activeTab.value = 0;
        dlgOpen.value = true;

        toast.add({
            severity: 'success',
            summary: 'JSON importado',
            detail: `"${json.titulo}" carregado. Revise e salve.`,
            life: 3000
        });
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro ao ler JSON', detail: e?.message, life: 4000 });
    }
}

// ── Helpers de exibição ───────────────────────────────────────
function tipoLabel(tipo) {
    return tipo === 'admin' ? 'Somente Admin' : 'Usuários';
}
function tipoSeverity(tipo) {
    return tipo === 'admin' ? 'danger' : 'info';
}
function relatedCount(doc) {
    return doc.docs_relacionados?.length || 0;
}
function mediasCount(doc) {
    return Array.isArray(doc.medias) ? doc.medias.filter((m) => m.url).length : 0;
}
</script>

<template>
    <ConfirmDialog />

    <!-- Input oculto para importação de JSON -->
    <input ref="jsonFileInputRef" type="file" accept=".json,application/json" style="display: none" @change="onJsonFileChange" />

    <div class="flex flex-col gap-4 p-4">
        <!-- Header -->
        <div class="cfg-subheader">
            <div class="cfg-subheader__icon"><i class="pi pi-book" /></div>
            <div class="min-w-0 flex-1">
                <div class="cfg-subheader__title">Documentação do Sistema</div>
                <div class="cfg-subheader__sub">Artigos de ajuda exibidos dinamicamente nas páginas.</div>
            </div>
            <!-- Desktop actions -->
            <div class="hidden xl:flex items-center gap-2 shrink-0">
                <Button icon="pi pi-refresh" severity="secondary" outlined rounded size="small" :loading="loading" @click="load" />
                <Button icon="pi pi-upload" label="Importar JSON" severity="secondary" outlined size="small" v-tooltip.bottom="'Carrega um arquivo .json gerado pelo assistente'" @click="triggerJsonImport" />
                <Button icon="pi pi-comment" label="Prompt" severity="secondary" outlined size="small" v-tooltip.bottom="'Ver instruções para gerar documentação com IA'" @click="promptDlgOpen = true" />
                <Button icon="pi pi-plus" label="Novo documento" size="small" @click="abrirDialog()" />
            </div>
            <!-- Mobile actions -->
            <div class="flex xl:hidden items-center gap-2 shrink-0">
                <Button icon="pi pi-refresh" severity="secondary" outlined rounded size="small" :loading="loading" @click="load" />
                <Button icon="pi pi-upload" severity="secondary" outlined rounded size="small" v-tooltip.bottom="'Importar JSON'" @click="triggerJsonImport" />
                <Button icon="pi pi-comment" severity="secondary" outlined rounded size="small" v-tooltip.bottom="'Prompt IA'" @click="promptDlgOpen = true" />
                <Button icon="pi pi-plus" rounded size="small" @click="abrirDialog()" />
            </div>
        </div>
        <!-- ── Cards de saúde ──────────────────────────────────── -->
        <div class="flex flex-wrap gap-2.5">
            <!-- Total -->
            <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] min-w-[110px]">
                <div class="text-[1.35rem] font-bold leading-none text-[var(--text-color)]">{{ totalDocs }}</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75">Total de docs</div>
            </div>

            <!-- OK -->
            <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border min-w-[110px]" style="border-color: color-mix(in srgb, #22c55e 25%, transparent); background: color-mix(in srgb, #22c55e 5%, var(--surface-card))">
                <div class="text-[1.35rem] font-bold leading-none text-green-600">{{ docsOk.length }}</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 flex items-center gap-1"><i class="pi pi-thumbs-up text-green-500 text-[10px]" />Bem avaliadas</div>
            </div>

            <!-- Atenção — clicável para filtrar -->
            <div
                class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border min-w-[110px] cursor-pointer transition-all"
                :style="
                    filtroAtencao
                        ? 'border-color: #ef4444; background: color-mix(in srgb, #ef4444 10%, var(--surface-card)); box-shadow: 0 0 0 3px color-mix(in srgb, #ef4444 15%, transparent)'
                        : 'border-color: color-mix(in srgb, #ef4444 25%, transparent); background: color-mix(in srgb, #ef4444 5%, var(--surface-card))'
                "
                v-tooltip.bottom="filtroAtencao ? 'Clique para ver todas' : 'Clique para filtrar'"
                @click="filtroAtencao = !filtroAtencao"
            >
                <div class="text-[1.35rem] font-bold leading-none text-red-500 flex items-center gap-1.5">
                    {{ docsAtencao.length }}
                    <i v-if="docsAtencao.length" class="pi pi-exclamation-triangle text-[1rem] text-red-400" />
                </div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 flex items-center gap-1"><i class="pi pi-thumbs-down text-red-400 text-[10px]" />Precisam de atenção</div>
            </div>

            <!-- Sem dados -->
            <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] min-w-[110px]">
                <div class="text-[1.35rem] font-bold leading-none text-[var(--text-color-secondary)]">{{ docsSemDados.length }}</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-60">Sem votos</div>
            </div>

            <!-- Mais útil -->
            <div
                v-if="docMaisUtil"
                class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-0"
                style="border-color: color-mix(in srgb, var(--primary-color) 30%, transparent); background: color-mix(in srgb, var(--primary-color) 5%, var(--surface-card))"
            >
                <div class="text-[1rem] font-semibold truncate text-[var(--primary-color)]">{{ docMaisUtil.titulo }}</div>
                <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 flex items-center gap-1">
                    <i class="pi pi-star text-amber-400 text-[10px]" />Mais útil
                    <span class="ml-1 opacity-60">({{ docMaisUtil.votos_util }} 👍)</span>
                </div>
            </div>
        </div>

        <!-- Banner de alerta quando há docs com problema -->
        <div
            v-if="docsAtencao.length && !filtroAtencao"
            class="flex items-center gap-2.5 px-3.5 py-2.5 rounded-md border text-[1rem] text-[var(--text-color)]"
            style="background: color-mix(in srgb, #f59e0b 8%, var(--surface-card)); border-color: color-mix(in srgb, #f59e0b 35%, transparent)"
        >
            <i class="pi pi-exclamation-triangle text-amber-500 shrink-0" />
            <span>
                <strong>{{ docsAtencao.length }} documento{{ docsAtencao.length > 1 ? 's' : '' }}</strong>
                {{ docsAtencao.length > 1 ? 'estão recebendo' : 'está recebendo' }} mais de 30% de votos negativos.
                <button class="underline text-[var(--primary-color)] ml-1" @click="filtroAtencao = true">Ver agora</button>
            </span>
        </div>

        <!-- ── Tabela ──────────────────────────────────────────── -->
        <div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] overflow-hidden">
            <DataTable
                :value="docsFiltrados"
                :loading="loading"
                v-model:filters="filters"
                :globalFilterFields="['titulo', 'pagina_path', 'categoria']"
                filterDisplay="menu"
                paginator
                :rows="10"
                :rowsPerPageOptions="[5, 10, 25, 50]"
                paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
                dataKey="id"
                removableSort
                class=""
                :emptyMessage="loading ? ' ' : filtroAtencao ? 'Nenhum documento com problema.' : 'Nenhum documento encontrado.'"
                :rowClass="(data) => (saudeDoc(data) === 'atencao' ? 'row-atencao' : '')"
            >
                <template #header>
                    <div class="flex items-center justify-between px-1 py-1 gap-2">
                        <div v-if="filtroAtencao" class="flex items-center gap-2">
                            <span class="text-[1rem] font-semibold text-red-500 flex items-center gap-1"> <i class="pi pi-filter" />Filtrando: precisam de atenção </span>
                            <button class="text-[1rem] text-[var(--text-color-secondary)] underline" @click="filtroAtencao = false">Limpar</button>
                        </div>
                        <div v-else class="flex-1" />
                        <IconField>
                            <InputIcon class="pi pi-search" />
                            <InputText v-model="filters['global'].value" placeholder="Buscar por título ou página…" class="w-72" />
                        </IconField>
                    </div>
                </template>

                <!-- Título + badges -->
                <Column field="titulo" header="Documento" sortable style="min-width: 220px">
                    <template #body="{ data }">
                        <div class="flex flex-col gap-1">
                            <div class="flex items-center gap-2 flex-wrap">
                                <span class="font-semibold text-[1rem]">{{ data.titulo }}</span>
                                <Tag :value="tipoLabel(data.tipo_acesso)" :severity="tipoSeverity(data.tipo_acesso)" class="text-[1rem]" />
                                <Tag v-if="!data.ativo" value="Inativo" severity="secondary" class="text-[1rem]" />
                                <span
                                    v-if="data.exibir_no_faq"
                                    class="inline-flex items-center text-[1rem] font-bold px-1.5 py-px rounded border"
                                    style="background: color-mix(in srgb, var(--primary-color) 15%, transparent); color: var(--primary-color); border-color: color-mix(in srgb, var(--primary-color) 30%, transparent); letter-spacing: 0.05em"
                                    >FAQ</span
                                >
                            </div>
                            <div class="flex items-center gap-3 text-[1rem] text-[var(--text-color-secondary)] opacity-70">
                                <span v-if="data.categoria"><i class="pi pi-tag mr-1" />{{ data.categoria }}</span>
                                <span v-if="relatedCount(data)"><i class="pi pi-link mr-1" />{{ relatedCount(data) }}</span>
                                <span v-if="mediasCount(data)"><i class="pi pi-image mr-1" />{{ mediasCount(data) }}</span>
                            </div>
                        </div>
                    </template>
                </Column>

                <!-- Página -->
                <Column field="pagina_path" header="Página" sortable style="min-width: 160px">
                    <template #body="{ data }">
                        <span class="text-[1rem] font-mono text-[var(--text-color-secondary)]">{{ data.pagina_path }}</span>
                    </template>
                </Column>

                <!-- Saúde / Votos -->
                <Column header="Votos" style="min-width: 130px; white-space: nowrap">
                    <template #body="{ data }">
                        <div class="flex items-center gap-2">
                            <!-- Sem votos suficientes -->
                            <span v-if="saudeDoc(data) === 'sem_dados'" class="text-[1rem] text-[var(--text-color-secondary)] opacity-40 italic"> sem dados </span>
                            <template v-else>
                                <!-- Indicador de saúde -->
                                <div
                                    class="w-2 h-2 rounded-full shrink-0"
                                    :class="saudeDoc(data) === 'atencao' ? 'bg-red-500 animate-pulse' : 'bg-green-500'"
                                    v-tooltip.top="saudeDoc(data) === 'atencao' ? `${pctNegativo(data)}% negativos — precisa de atenção` : `${pctNegativo(data)}% negativos — OK`"
                                />
                                <!-- Contadores -->
                                <div class="flex items-center gap-1.5 text-[1rem]">
                                    <span class="flex items-center gap-0.5 text-green-600"> <i class="pi pi-thumbs-up text-[10px]" />{{ data.votos_util || 0 }} </span>
                                    <span class="text-[var(--surface-border)]">·</span>
                                    <span class="flex items-center gap-0.5 text-red-500"> <i class="pi pi-thumbs-down text-[10px]" />{{ data.votos_nao_util || 0 }} </span>
                                </div>
                                <!-- % negativo para docs em atenção -->
                                <span v-if="saudeDoc(data) === 'atencao'" class="text-[1rem] text-red-400 font-semibold"> {{ pctNegativo(data) }}% </span>
                            </template>
                        </div>
                    </template>
                </Column>

                <!-- Modificado em -->
                <Column field="updated_at" header="Modificado em" sortable style="min-width: 130px; white-space: nowrap">
                    <template #body="{ data }">
                        <span class="text-[1rem] text-[var(--text-color-secondary)]">{{ fmtDate(data.updated_at) }}</span>
                    </template>
                </Column>

                <!-- Ações -->
                <Column header="" style="width: 110px; text-align: right">
                    <template #body="{ data }">
                        <div class="flex items-center justify-end gap-1">
                            <Button icon="pi pi-eye" text rounded size="small" severity="info" v-tooltip.top="'Visualizar'" @click="abrirPreview(data)" />
                            <Button icon="pi pi-pencil" text rounded size="small" severity="secondary" v-tooltip.top="'Editar'" @click="abrirDialog(data)" />
                            <Button icon="pi pi-trash" text rounded size="small" severity="danger" v-tooltip.top="'Excluir'" @click="excluir(data)" />
                        </div>
                    </template>
                </Column>
            </DataTable>
        </div>
    </div>
    <!-- /px-3 content wrapper -->

    <!-- ══ Dialog de preview ══════════════════════════════════ -->
    <Dialog v-model:visible="previewOpen" modal :draggable="false" :style="{ width: '520px', maxWidth: '95vw' }" @hide="previewFaqAbertos = {}">
        <template #header>
            <div class="flex items-center gap-2">
                <i class="pi pi-question-circle text-blue-500" />
                <span class="font-semibold">{{ previewDoc?.titulo }}</span>
                <Tag :value="tipoLabel(previewDoc?.tipo_acesso)" :severity="tipoSeverity(previewDoc?.tipo_acesso)" class="text-[1rem] ml-1" />
                <span
                    v-if="previewDoc?.exibir_no_faq"
                    class="inline-flex items-center text-[1rem] font-bold px-1.5 py-px rounded border ml-1"
                    style="background: color-mix(in srgb, var(--primary-color) 15%, transparent); color: var(--primary-color); border-color: color-mix(in srgb, var(--primary-color) 30%, transparent); letter-spacing: 0.05em"
                    >FAQ</span
                >
            </div>
        </template>

        <div v-if="previewDoc" class="flex flex-col gap-4 py-1">
            <div class="text-[1rem] font-mono text-[var(--text-color-secondary)] bg-[var(--surface-ground)] rounded-md px-3 py-2">
                <i class="pi pi-map-marker mr-1 opacity-60" />{{ previewDoc.pagina_path }}
                <span v-if="previewDoc.categoria" class="ml-2 opacity-60">· {{ previewDoc.categoria }}</span>
            </div>

            <div v-if="previewDoc.conteudo" class="text-[1rem] leading-relaxed text-[var(--text-color-secondary)] ql-content" v-html="previewDoc.conteudo" />

            <!-- Mídias -->
            <template v-if="previewDoc.medias?.length">
                <div v-for="(m, idx) in previewDoc.medias.filter((m) => m.url)" :key="idx">
                    <img v-if="m.tipo === 'imagem'" :src="m.url" class="w-full rounded-md border border-[var(--surface-border)]" :alt="previewDoc.titulo" />
                    <div v-else-if="m.tipo === 'video'" class="relative w-full rounded-md overflow-hidden border border-[var(--surface-border)]" style="padding-top: 56.25%">
                        <iframe :src="m.url" frameborder="0" allowfullscreen class="absolute inset-0 w-full h-full" />
                    </div>
                </div>
            </template>

            <!-- FAQ itens preview -->
            <div v-if="previewFaqItens.length" class="border-t border-[var(--surface-border)] pt-3">
                <div class="text-[1rem] font-bold uppercase tracking-wider text-[var(--text-color-secondary)] mb-2"><i class="pi pi-comments mr-1" />Perguntas frequentes</div>
                <div class="flex flex-col gap-1">
                    <div
                        v-for="item in previewFaqItens"
                        :key="item.id"
                        class="rounded-md overflow-hidden mb-px border bg-[var(--surface-ground)]"
                        :style="previewFaqAbertos[item.id] ? 'border-color: color-mix(in srgb, var(--primary-color) 30%, transparent)' : 'border-color: var(--surface-border)'"
                    >
                        <button class="w-full flex items-center justify-between gap-2 px-3 py-2 text-[1rem] font-medium bg-transparent border-none cursor-pointer text-left text-[var(--text-color)]" @click="togglePreviewFaq(item.id)">
                            <span>{{ item.pergunta }}</span>
                            <i class="pi opacity-40 shrink-0" :class="previewFaqAbertos[item.id] ? 'pi-chevron-up' : 'pi-chevron-down'" />
                        </button>
                        <div v-if="previewFaqAbertos[item.id] && item.resposta" class="px-3 pb-2 text-[1rem] text-[var(--text-color-secondary)] leading-relaxed ql-content" v-html="item.resposta" />
                    </div>
                </div>
            </div>

            <!-- Veja também -->
            <div v-if="previewRelated.length" class="border-t border-[var(--surface-border)] pt-3">
                <div class="text-[1rem] font-bold uppercase tracking-wider text-[var(--text-color-secondary)] mb-2"><i class="pi pi-link mr-1" />Veja também</div>
                <div class="flex flex-col gap-1">
                    <div v-for="rel in previewRelated" :key="rel.id" class="flex items-center gap-2 px-3 py-2 rounded-md bg-[var(--surface-ground)] text-[1rem] text-[var(--primary-color)]">
                        <i class="pi pi-arrow-right" />
                        <span class="font-medium">{{ rel.titulo }}</span>
                        <span class="text-[1rem] text-[var(--text-color-secondary)] font-mono ml-auto">{{ rel.pagina_path }}</span>
                    </div>
                </div>
            </div>
        </div>

        <template #footer>
            <Button label="Fechar" severity="secondary" outlined @click="previewOpen = false" />
            <Button
                label="Editar"
                icon="pi pi-pencil"
                @click="
                    previewOpen = false;
                    abrirDialog(previewDoc);
                "
            />
        </template>
    </Dialog>

    <!-- ══ Dialog de criação / edição ═════════════════════════ -->
    <Dialog v-model:visible="dlgOpen" modal :draggable="false" :header="editId ? 'Editar documento' : 'Novo documento'" :style="{ width: '680px', maxWidth: '95vw' }">
        <!-- Tabs de navegação -->
        <div class="flex gap-0 border-b border-[var(--surface-border)] -mx-6 px-6">
            <button
                v-for="(tab, i) in ['Conteúdo', 'Perguntas FAQ', 'Mídias', 'Configurações']"
                :key="i"
                class="flex items-center px-4 py-2.5 text-[1rem] font-medium bg-transparent border-none border-b-2 -mb-px cursor-pointer transition-colors whitespace-nowrap"
                :class="activeTab === i ? 'text-[var(--primary-color)] border-b-[var(--primary-color)]' : 'text-[var(--text-color-secondary)] border-b-transparent hover:text-[var(--text-color)]'"
                :style="activeTab === i ? 'border-bottom-color: var(--primary-color)' : 'border-bottom-color: transparent'"
                @click="activeTab = i"
            >
                <i class="mr-1.5" :class="['pi', i === 0 ? 'pi-align-left' : i === 1 ? 'pi-comments' : i === 2 ? 'pi-image' : 'pi-cog']" />
                {{ tab }}
                <span v-if="i === 1 && form._faq_itens.length" class="inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 ml-1.5 rounded-full bg-[var(--primary-color)] text-white text-[1rem] font-bold">{{
                    form._faq_itens.length
                }}</span>
            </button>
        </div>

        <div class="flex flex-col gap-5 pt-4">
            <!-- ── Aba 0: Conteúdo ─────────────────────────────────── -->
            <template v-if="activeTab === 0">
                <div>
                    <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Título *</label>
                    <InputText v-model="form.titulo" class="w-full mt-1" placeholder="Ex.: Como fazer login, Como trocar a senha…" />
                </div>
                <div>
                    <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Página de exibição *</label>
                    <Select v-model="form.pagina_path" :options="pageSelectOptions" optionLabel="label" optionValue="path" class="w-full mt-1" filter filterPlaceholder="Buscar página…" placeholder="Selecione a página…">
                        <template #option="{ option }">
                            <div class="flex items-center justify-between gap-2 w-full min-w-0">
                                <span class="truncate text-[1rem]">{{ option.label }}</span>
                                <span v-if="docsCountByPath.get(option.path)" class="shrink-0 inline-flex items-center gap-1 text-[0.6rem] font-bold px-1.5 py-0.5 rounded-full bg-[var(--primary-color)] text-white opacity-80">
                                    <i class="pi pi-file" style="font-size: 0.6rem" />
                                    {{ docsCountByPath.get(option.path) }} doc{{ docsCountByPath.get(option.path) > 1 ? 's' : '' }}
                                </span>
                            </div>
                        </template>
                    </Select>
                    <InputText v-if="isCustomPath" v-model="form._custom_path" class="w-full mt-2" placeholder="/caminho/da/pagina" />
                    <div v-if="resolvedPath" class="text-[1rem] font-mono text-[var(--text-color-secondary)] mt-1 opacity-70">path: {{ resolvedPath }}</div>
                </div>
                <div>
                    <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Conteúdo</label>
                    <Editor v-model="form.conteudo" class="mt-1" editorStyle="height: 220px" />
                </div>
                <div>
                    <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Docs relacionados <span class="opacity-50 ml-1">(exibidos no rodapé como "Veja também")</span></label>
                    <MultiSelect
                        v-model="form.docs_relacionados"
                        :options="docsRelOptions"
                        optionLabel="label"
                        optionValue="value"
                        class="w-full mt-1"
                        filter
                        display="chip"
                        placeholder="Selecione docs relacionados…"
                        :maxSelectedLabels="4"
                        emptyFilterMessage="Nenhum doc encontrado"
                        emptyMessage="Nenhum doc cadastrado ainda"
                    />
                </div>
            </template>

            <!-- ── Aba 1: Perguntas FAQ ────────────────────────────── -->
            <template v-if="activeTab === 1">
                <!-- Habilitar FAQ -->
                <div class="flex items-center justify-between rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] px-4 py-3">
                    <div>
                        <div class="text-[1rem] font-medium">Exibir no portal FAQ</div>
                        <div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Quando ativo, este documento e suas perguntas aparecem na página de FAQ do sistema.</div>
                    </div>
                    <ToggleSwitch v-model="form.exibir_no_faq" />
                </div>

                <!-- Categoria -->
                <div>
                    <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Categoria <span class="opacity-50 ml-1">(agrupa no portal FAQ)</span></label>
                    <AutoComplete
                        v-model="form.categoria"
                        :suggestions="categorias.filter((c) => !form.categoria || c.toLowerCase().includes(String(form.categoria).toLowerCase()))"
                        class="w-full mt-1"
                        placeholder="Ex.: Conta, Agenda, Pagamentos…"
                        @complete="() => {}"
                    />
                    <div v-if="categorias.length" class="flex flex-wrap gap-1 mt-2">
                        <button
                            v-for="cat in categorias"
                            :key="cat"
                            class="inline-flex items-center text-[1rem] font-medium px-2 py-0.5 rounded-full border cursor-pointer transition-all"
                            :class="
                                form.categoria === cat
                                    ? 'text-[var(--primary-color)] border-[var(--primary-color)]'
                                    : 'text-[var(--text-color-secondary)] border-[var(--surface-border)] bg-[var(--surface-ground)] hover:border-[var(--primary-color)] hover:text-[var(--primary-color)]'
                            "
                            :style="form.categoria === cat ? 'background: color-mix(in srgb, var(--primary-color) 12%, transparent); border-color: color-mix(in srgb, var(--primary-color) 35%, transparent)' : ''"
                            @click="form.categoria = form.categoria === cat ? '' : cat"
                        >
                            {{ cat }}
                        </button>
                    </div>
                </div>

                <!-- Lista de itens FAQ -->
                <div>
                    <div class="flex items-center justify-between mb-3">
                        <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Perguntas e respostas</label>
                        <Button icon="pi pi-plus" label="Adicionar pergunta" text size="small" @click="addFaqItem" />
                    </div>

                    <div v-if="faqLoading" class="flex justify-center py-6">
                        <i class="pi pi-spinner pi-spin opacity-40" />
                    </div>

                    <div v-else-if="!form._faq_itens.length" class="text-[1rem] text-[var(--text-color-secondary)] italic text-center py-6 border border-dashed border-[var(--surface-border)] rounded-md">
                        Nenhuma pergunta adicionada ainda.<br />
                        <button class="text-[var(--primary-color)] mt-1 underline text-[1rem]" @click="addFaqItem">Adicionar a primeira</button>
                    </div>

                    <div v-else class="flex flex-col gap-3">
                        <div v-for="(item, idx) in form._faq_itens" :key="idx" class="p-3.5 border border-[var(--surface-border)] rounded-md bg-[var(--surface-ground)]">
                            <div class="flex items-center justify-between mb-2">
                                <span class="text-[1rem] font-semibold text-[var(--text-color-secondary)] opacity-60">Pergunta {{ idx + 1 }}</span>
                                <div class="flex items-center gap-1">
                                    <ToggleSwitch v-model="item.ativo" v-tooltip.top="'Ativo'" />
                                    <Button icon="pi pi-trash" text rounded size="small" severity="danger" @click="removeFaqItem(idx)" />
                                </div>
                            </div>
                            <InputText v-model="item.pergunta" class="w-full mb-2" placeholder="Ex.: Como redefinir minha senha?" />
                            <Editor v-model="item.resposta" editorStyle="height: 120px" />
                        </div>
                    </div>
                </div>
            </template>

            <!-- ── Aba 2: Mídias ──────────────────────────────────── -->
            <template v-if="activeTab === 2">
                <div>
                    <div class="flex items-center justify-between mb-2">
                        <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Imagens e vídeos</label>
                        <Button icon="pi pi-plus" label="Adicionar" text size="small" @click="addMedia" />
                    </div>

                    <div v-if="!form.medias.length" class="text-[1rem] text-[var(--text-color-secondary)] italic">Nenhuma mídia adicionada.</div>

                    <div v-for="(m, idx) in form.medias" :key="idx" class="flex items-center gap-2 mb-2 p-2 rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)]">
                        <Select
                            v-model="m.tipo"
                            :options="[
                                { label: 'Imagem', value: 'imagem' },
                                { label: 'Vídeo (embed)', value: 'video' }
                            ]"
                            optionLabel="label"
                            optionValue="value"
                            class="w-36 shrink-0"
                        />
                        <template v-if="m.tipo === 'imagem'">
                            <input
                                type="file"
                                accept="image/*"
                                style="display: none"
                                :ref="
                                    (el) => {
                                        if (el) fileInputRefs[idx] = el;
                                    }
                                "
                                @change="uploadImagem(idx, $event)"
                            />
                            <div v-if="!m.url" class="flex-1">
                                <Button icon="pi pi-upload" label="Enviar imagem" severity="secondary" outlined :loading="uploadingIdx.has(idx)" class="w-full" @click="triggerUpload(idx)" />
                            </div>
                            <div v-else class="flex items-center gap-2 flex-1 min-w-0">
                                <img :src="m.url" class="w-14 h-14 object-cover rounded-md border border-[var(--surface-border)] shrink-0" :alt="`Imagem ${idx + 1}`" />
                                <div class="flex flex-col gap-1 flex-1 min-w-0">
                                    <span class="text-[1rem] font-mono truncate text-[var(--text-color-secondary)]">{{ m.url }}</span>
                                    <Button icon="pi pi-refresh" label="Trocar imagem" text size="small" severity="secondary" :loading="uploadingIdx.has(idx)" @click="triggerUpload(idx)" />
                                </div>
                            </div>
                        </template>
                        <InputText v-else v-model="m.url" class="flex-1" placeholder="https://www.youtube.com/embed/ID" />
                        <Button icon="pi pi-trash" text rounded size="small" severity="danger" @click="removeMedia(idx)" />
                    </div>
                </div>
            </template>

            <!-- ── Aba 3: Configurações ───────────────────────────── -->
            <template v-if="activeTab === 3">
                <div>
                    <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Visibilidade</label>
                    <div class="mt-1">
                        <SelectButton v-model="form.tipo_acesso" :options="tipoAcessoOptions" optionLabel="label" optionValue="value" />
                    </div>
                </div>
                <div class="flex items-end gap-4">
                    <div class="flex-1">
                        <label class="text-[1rem] text-[var(--text-color-secondary)] font-medium">Ordem de exibição</label>
                        <InputNumber v-model="form.ordem" class="w-full mt-1" :min="0" />
                    </div>
                    <div class="flex items-center gap-2 pb-1">
                        <ToggleSwitch v-model="form.ativo" inputId="doc-ativo" />
                        <label for="doc-ativo" class="text-[1rem] cursor-pointer select-none">Ativo</label>
                    </div>
                </div>
            </template>
        </div>

        <template #footer>
            <Button label="Cancelar" severity="secondary" outlined @click="dlgOpen = false" />
            <Button :label="editId ? 'Salvar alterações' : 'Criar documento'" icon="pi pi-check" :disabled="!formValid" :loading="saving" @click="salvar" />
        </template>
    </Dialog>
    <!-- ══ Dialog de Prompt IA ════════════════════════════════ -->
    <Dialog v-model:visible="promptDlgOpen" modal :draggable="false" header="Gerar documentação com IA" :style="{ width: '680px', maxWidth: '95vw' }" pt:mask:class="backdrop-blur-xs">
        <div class="flex flex-col gap-4">
            <!-- Instrução humana -->
            <div class="flex items-start gap-3 rounded-[6px] border border-[var(--surface-border)] bg-[var(--surface-ground)] p-4">
                <i class="pi pi-info-circle text-blue-500 text-lg shrink-0 mt-0.5" />
                <div class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">
                    Usando o <strong class="text-[var(--text-color)]">Claude</strong>, envie o arquivo <code class="text-[1rem] bg-[var(--surface-border)] px-1.5 py-0.5 rounded">.vue</code> da página que deseja documentar. O Claude irá analisar os
                    componentes, identificar os <code class="text-[1rem] bg-[var(--surface-border)] px-1.5 py-0.5 rounded">id</code>s dos elementos, reproduzir visualmente os cards e seções dentro do conteúdo, criar as perguntas FAQ, definir a rota
                    correta de exibição e retornar um arquivo <code class="text-[1rem] bg-[var(--surface-border)] px-1.5 py-0.5 rounded">.json</code> pronto para importar aqui.
                </div>
            </div>

            <!-- Prompt copiável -->
            <div class="relative">
                <div class="flex items-center justify-between mb-2">
                    <span class="text-[1rem] font-bold uppercase tracking-wider text-[var(--text-color-secondary)] opacity-60"> <i class="pi pi-clipboard mr-1" />Prompt para o Claude </span>
                    <Button icon="pi pi-copy" label="Copiar" size="small" text class="rounded-full" @click="copiarPrompt" />
                </div>
                <pre class="prompt-pre">
Você é um especialista em documentação de produto SaaS voltado para psicólogos e terapeutas.

Vou te enviar o código-fonte de uma página Vue.js do sistema. Sua tarefa é:

1. ANALISAR o código completo — componentes, props, lógica, rotas, dados carregados do Supabase e regras de negócio visíveis
2. IDENTIFICAR todos os elementos com id= e quais não têm (sugerindo os que deveriam ter para o sistema de highlight da ajuda)
3. REPRODUZIR visualmente no campo "conteudo" os cards, timelines, tabelas e seções mais importantes usando HTML inline com estilos CSS, exatamente como foi feito nos exemplos abaixo — para que o usuário veja o elemento real dentro da documentação
4. CRIAR links de highlight usando o padrão: &lt;a data-highlight="id-do-elemento" data-route="/rota-da-pagina" href="#"&gt;Ver na tela&lt;/a&gt;
5. DEFINIR a rota correta no campo "pagina_path" baseada nos comentários, nome do componente e router-links encontrados no código
6. GERAR entre 8 e 12 perguntas FAQ reais que um terapeuta iniciante faria sobre essa tela
7. RETORNAR um único arquivo .json com a estrutura abaixo, pronto para importar no sistema

ESTRUTURA DO JSON (siga exatamente):
{
  "titulo": "string — título claro e objetivo",
  "conteudo": "string — HTML rico com &lt;h2&gt;, &lt;h3&gt;, &lt;h4&gt;, &lt;p&gt;, &lt;ul&gt;, &lt;li&gt;, &lt;strong&gt;, cards reproduzidos em HTML inline e links data-highlight",
  "categoria": "string — ex: Agenda, Pacientes, Financeiro, Configurações",
  "exibir_no_faq": true,
  "tipo_acesso": "usuario",
  "pagina_path": "string — rota exata ex: /therapist, /therapist/agenda",
  "ordem": 1,
  "ativo": true,
  "medias": [{ "tipo": "imagem", "url": "" }],
  "_faq_itens": [
    {
      "pergunta": "string — pergunta real de um usuário iniciante",
      "resposta": "string — resposta clara e direta",
      "ordem": 0,
      "ativo": true
    }
  ]
}

REGRAS OBRIGATÓRIAS:
- "conteudo" deve ser HTML válido em português do Brasil
- Reproduza visualmente pelo menos 2 elementos da tela (cards, timeline, etc.) usando HTML+CSS inline
- Explique TODOS os botões, campos, filtros, modais e fluxos visíveis no código
- Se houver regras de negócio (ex: item padrão não pode ser excluído, campo obrigatório), documente
- Para cada elemento importante que tiver id= no código, crie um link data-highlight correspondente
- Se um elemento importante NÃO tiver id=, mencione que o id precisa ser adicionado ao componente
- Links data-highlight funcionam tanto no "conteudo" quanto nas "respostas" do _faq_itens — use em ambos sempre que referenciar um elemento da tela
- Nas respostas do FAQ, quando mencionar um card ou seção específica, sempre inclua o link data-highlight correspondente e, se houver uma rota dedicada para aquela funcionalidade (ex: $router.push encontrado no código), inclua também o caminho em &lt;code&gt; ou como texto
- "medias" deve ter 1 item vazio como placeholder
- Não invente funcionalidades que não existem no código

Agora analise o arquivo .vue anexo e gere o JSON completo:</pre
                >
            </div>
        </div>

        <template #footer>
            <div class="flex items-center justify-between gap-2">
                <span class="text-[1rem] text-[var(--text-color-secondary)] opacity-60"> <i class="pi pi-lightbulb mr-1" />Cole o prompt no Claude e anexe o arquivo .vue da página </span>
                <div class="flex gap-2">
                    <Button label="Fechar" severity="secondary" outlined class="rounded-full" @click="promptDlgOpen = false" />
                    <Button label="Copiar prompt" icon="pi pi-copy" class="rounded-full" @click="copiarPrompt" />
                </div>
            </div>
        </template>
    </Dialog>
</template>

<style scoped>
.prompt-pre {
    font-family: var(--font-family, monospace);
    font-size: 0.75rem;
    line-height: 1.65;
    color: var(--text-color);
    background: var(--surface-ground);
    border: 1px solid var(--surface-border);
    border-radius: 6px;
    padding: 1rem;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 380px;
    overflow-y: auto;
    margin: 0;
}

:deep(.row-atencao td) {
    background: color-mix(in srgb, #ef4444 4%, var(--surface-card)) !important;
}
:deep(.row-atencao:hover td) {
    background: color-mix(in srgb, #ef4444 8%, var(--surface-card)) !important;
}
</style>
