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

import { useDocuments } from './composables/useDocuments'
import DocumentCard from './components/DocumentCard.vue'
import DocumentUploadDialog from './components/DocumentUploadDialog.vue'
import DocumentPreviewDialog from './components/DocumentPreviewDialog.vue'
import DocumentGenerateDialog from './components/DocumentGenerateDialog.vue'
import DocumentSignatureDialog from './components/DocumentSignatureDialog.vue'
import DocumentShareDialog from './components/DocumentShareDialog.vue'

const route = useRoute()
const router = useRouter()
const toast = useToast()
const confirm = useConfirm()

// ── Props (pode receber patientId via route ou prop) ────────
const props = defineProps({
    patientId: { type: String, default: null },
    patientName: { type: String, default: '' },
    embedded: { type: Boolean, default: false }
})

const resolvedPatientId = computed(() => props.patientId || route.params.id || null)

const {
    documents, loading, error, filters, usedTags, stats,
    TIPOS_DOCUMENTO,
    fetchDocuments, upload, update, remove, restore,
    download, getPreviewUrl, fetchUsedTags, clearFilters,
    formatSize, mimeIcon
} = useDocuments(() => resolvedPatientId.value)

// ── Dialogs ─────────────────────────────────────────────────

const uploadDlg = ref(false)
const previewDlg = ref(false)
const generateDlg = ref(false)
const signatureDlg = ref(false)
const shareDlg = ref(false)

const selectedDoc = ref(null)
const previewUrl = ref('')

// ── Mobile menu ─────────────────────────────────────────────

const mobileMenuRef = ref(null)
const mobileMenuItems = computed(() => [
    { label: 'Upload', icon: 'pi pi-upload', command: () => uploadDlg.value = true },
    { label: 'Gerar documento', icon: 'pi pi-file-pdf', command: () => generateDlg.value = true },
    { separator: true },
    { label: 'Atualizar', icon: 'pi pi-refresh', command: () => fetchDocuments() }
])

// ── Hero sticky ─────────────────────────────────────────────

const headerEl = ref(null)
const headerSentinelRef = ref(null)
const headerStuck = ref(false)
let _observer = null

// ── Mobile dialogs ──────────────────────────────────────────

const filtersDlgOpen = ref(false)

// ── Lifecycle ───────────────────────────────────────────────

onMounted(async () => {
    if (!props.embedded) {
        const rootMargin = `${document.querySelector('.l2-main') ? '0px' : '-56px'} 0px 0px 0px`
        _observer = new IntersectionObserver(
            ([entry]) => { headerStuck.value = !entry.isIntersecting },
            { threshold: 0, rootMargin }
        )
        if (headerSentinelRef.value) _observer.observe(headerSentinelRef.value)
    }
    await Promise.all([fetchDocuments(), fetchUsedTags()])
})

onBeforeUnmount(() => {
    _observer?.disconnect()
})

// ── Acoes ───────────────────────────────────────────────────

async function onUploaded({ file, meta }) {
    try {
        await upload(file, resolvedPatientId.value, meta)
        toast.add({ severity: 'success', summary: 'Enviado', detail: file.name, life: 3000 })
        fetchUsedTags()
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Erro no upload', detail: e?.message })
    }
}

async function onPreview(doc) {
    selectedDoc.value = doc
    try {
        previewUrl.value = await getPreviewUrl(doc)
    } catch {
        previewUrl.value = ''
    }
    previewDlg.value = true
}

function onDownload(doc) {
    download(doc)
}

function onEdit(doc) {
    selectedDoc.value = doc
    // TODO: abrir dialog de edicao de metadados
    toast.add({ severity: 'info', summary: 'Em breve', detail: 'Edição de metadados será implementada.', life: 2000 })
}

function onDelete(doc) {
    confirm.require({
        message: `Excluir "${doc.nome_original}"? O arquivo será retido por 5 anos conforme LGPD/CFP.`,
        header: 'Confirmar exclusão',
        icon: 'pi pi-exclamation-triangle',
        acceptClass: 'p-button-danger',
        accept: async () => {
            try {
                await remove(doc.id)
                toast.add({ severity: 'success', summary: 'Excluído', detail: doc.nome_original, life: 2000 })
            } catch (e) {
                toast.add({ severity: 'error', summary: 'Erro', detail: e?.message })
            }
        }
    })
}

function onShare(doc) {
    selectedDoc.value = doc
    shareDlg.value = true
}

function onSign(doc) {
    selectedDoc.value = doc
    signatureDlg.value = true
}

function onGenerated() {
    fetchDocuments()
}

// ── Computed: filtro ativo ───────────────────────────────────

const hasActiveFilter = computed(() =>
    filters.value.tipo_documento || filters.value.tag || filters.value.search
)

// ── Watch filtros ───────────────────────────────────────────

watch(filters, () => fetchDocuments(), { deep: true })
</script>

<template>
    <!-- ══════════════════════════════════════════════════════════════
         EMBEDDED MODE — dentro do prontuário (sem hero, layout compacto)
       ══════════════════════════════════════════════════════════════ -->
    <div v-if="embedded">
        <!-- Header compacto: ações alinhadas à direita, sem label -->
        <div class="flex items-center justify-end gap-2 mb-4">
            <Button label="Upload" icon="pi pi-upload" size="small" outlined class="rounded-full" @click="uploadDlg = true" />
            <Button label="Template" icon="pi pi-file-pdf" size="small" class="rounded-full" @click="generateDlg = true" />
        </div>

        <!-- Loading -->
        <div v-if="loading" class="flex items-center justify-center py-12">
            <i class="pi pi-spinner pi-spin text-2xl text-[var(--text-color-secondary)]" />
        </div>

        <!-- Empty -->
        <div v-else-if="!documents.length" class="empty-rich">
            <div class="empty-rich__icon"><i class="pi pi-folder-open" /></div>
            <div class="empty-rich__title">Nenhum documento ainda</div>
            <div class="empty-rich__sub">Faça upload do primeiro laudo, receita, exame ou termo assinado deste paciente.</div>
            <Button v-if="resolvedPatientId" label="Enviar documento" icon="pi pi-upload" class="empty-rich__cta rounded-full" @click="uploadDlg = true" />
        </div>

        <!-- Lista -->
        <div v-else class="flex flex-col gap-2">
            <DocumentCard v-for="doc in documents" :key="doc.id" :doc="doc" @preview="onPreview" @download="onDownload" @edit="onEdit" @delete="onDelete" @share="onShare" @sign="onSign" />
        </div>

        <!-- Error -->
        <div v-if="error" class="mt-4 p-3 rounded-md bg-red-500/5 border border-red-500/20 text-sm text-red-500">
            <i class="pi pi-exclamation-circle mr-1" /> {{ error }}
        </div>
    </div>

    <!-- ══════════════════════════════════════════════════════════════
         PÁGINA FULL — hero sticky + stats + lista em card
       ══════════════════════════════════════════════════════════════ -->
    <template v-else>
        <!-- Sentinel -->
        <div ref="headerSentinelRef" class="h-px" />

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

            <div class="relative z-1 flex items-center gap-3">
                <!-- Voltar + Brand -->
                <div class="flex items-center gap-2 shrink-0">
                    <Button v-if="resolvedPatientId" icon="pi pi-arrow-left" text severity="secondary" class="h-9 w-9 rounded-full shrink-0" v-tooltip.bottom="'Voltar'" @click="router.back()" />
                    <div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
                        <i class="pi pi-file text-base" />
                    </div>
                    <div class="min-w-0 hidden lg:block">
                        <div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">Documentos</div>
                        <div class="text-[0.75rem] text-[var(--text-color-secondary)] truncate">
                            {{ resolvedPatientId ? (patientName || 'Paciente') : 'Todos os pacientes' }}
                        </div>
                    </div>
                </div>

                <!-- Ações desktop -->
                <div class="hidden xl:flex items-center gap-1 shrink-0 ml-auto">
                    <Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" v-tooltip.bottom="'Atualizar'" @click="fetchDocuments" />
                    <Button label="Gerar" icon="pi pi-file-pdf" severity="secondary" outlined size="small" class="rounded-full" :disabled="!resolvedPatientId" @click="generateDlg = true" />
                    <Button label="Upload" icon="pi pi-upload" size="small" class="rounded-full" :disabled="!resolvedPatientId" @click="uploadDlg = true" />
                </div>

                <!-- Mobile -->
                <div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
                    <Button icon="pi pi-filter" severity="secondary" outlined class="h-9 w-9 rounded-full" v-tooltip.bottom="'Filtros'" @click="filtersDlgOpen = true" />
                    <Button icon="pi pi-upload" class="h-9 w-9 rounded-full" :disabled="!resolvedPatientId" @click="uploadDlg = true" />
                    <Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => mobileMenuRef.toggle(e)" />
                    <Menu ref="mobileMenuRef" :model="mobileMenuItems" :popup="true" />
                </div>
            </div>
        </div>

        <!-- Dialog filtros mobile -->
        <Dialog v-model:visible="filtersDlgOpen" modal :draggable="false" pt:mask:class="backdrop-blur-xs" header="Filtros" class="w-[94vw] max-w-sm">
            <div class="flex flex-col gap-3 pt-1">
                <IconField>
                    <InputIcon class="pi pi-search" />
                    <InputText v-model="filters.search" placeholder="Buscar..." class="w-full" />
                </IconField>
                <Select v-model="filters.tipo_documento" :options="TIPOS_DOCUMENTO" optionLabel="label" optionValue="value" placeholder="Tipo" showClear class="w-full" />
                <Select v-if="usedTags.length" v-model="filters.tag" :options="usedTags.map(t => ({ label: t, value: t }))" optionLabel="label" optionValue="value" placeholder="Tag" showClear class="w-full" />
            </div>
            <template #footer>
                <Button v-if="hasActiveFilter" label="Limpar" icon="pi pi-filter-slash" severity="danger" outlined class="rounded-full mr-2" @click="clearFilters(); fetchDocuments()" />
                <Button label="Fechar" severity="secondary" outlined class="rounded-full" @click="filtersDlgOpen = false" />
            </template>
        </Dialog>

        <!-- Conteúdo -->
        <div class="px-3 md:px-4 pb-8 flex flex-col gap-3 xl:gap-4">
            <!-- Stats -->
            <div v-if="documents.length" class="grid grid-cols-2 md:grid-cols-4 gap-2">
                <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]">
                    <div class="text-[1.35rem] font-bold leading-none text-[var(--text-color)]">{{ stats.total }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 truncate">Total</div>
                </div>
                <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]">
                    <div class="text-[1.35rem] font-bold leading-none text-[var(--text-color)]">{{ formatSize(stats.tamanhoTotal) }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 truncate">Tamanho</div>
                </div>
                <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]">
                    <div class="text-[1.35rem] font-bold leading-none text-[var(--text-color)]">{{ Object.keys(stats.porTipo).length }}</div>
                    <div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 truncate">Tipos</div>
                </div>
                <div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border" :class="stats.pendentesRevisao ? 'border-amber-500/30 bg-amber-500/5' : 'border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]'">
                    <div class="text-[1.35rem] font-bold leading-none" :class="stats.pendentesRevisao ? 'text-amber-600' : 'text-[var(--text-color)]'">{{ stats.pendentesRevisao || 0 }}</div>
                    <div class="text-[1rem] opacity-75 truncate" :class="stats.pendentesRevisao ? 'text-amber-600' : 'text-[var(--text-color-secondary)]'">Pendentes</div>
                </div>
            </div>

            <!-- Tabela (card) -->
            <div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
                <!-- Header da tabela -->
                <div class="flex items-center justify-between gap-2 px-4 py-3 border-b border-[var(--surface-border,#e2e8f0)]">
                    <div class="flex items-center gap-2 min-w-0">
                        <i class="pi pi-list text-[var(--text-color-secondary)] opacity-60" />
                        <span class="font-semibold text-sm">Documentos</span>
                    </div>
                    <span class="inline-flex items-center justify-center min-w-[22px] h-[22px] px-1.5 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-[0.72rem] font-bold">{{ documents.length }}</span>
                </div>

                <!-- Filtros desktop -->
                <div class="hidden md:flex flex-wrap items-center gap-2 px-4 py-3 border-b border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)]/50">
                    <IconField>
                        <InputIcon class="pi pi-search" />
                        <InputText v-model="filters.search" placeholder="Buscar..." class="!w-[200px]" size="small" />
                    </IconField>
                    <Select v-model="filters.tipo_documento" :options="TIPOS_DOCUMENTO" optionLabel="label" optionValue="value" placeholder="Tipo" showClear class="!w-[160px]" size="small" />
                    <Select v-if="usedTags.length" v-model="filters.tag" :options="usedTags.map(t => ({ label: t, value: t }))" optionLabel="label" optionValue="value" placeholder="Tag" showClear class="!w-[140px]" size="small" />
                    <Button v-if="hasActiveFilter" icon="pi pi-filter-slash" severity="danger" text rounded size="small" v-tooltip.top="'Limpar filtros'" @click="clearFilters(); fetchDocuments()" />
                </div>

                <!-- Loading -->
                <div v-if="loading" class="flex items-center justify-center py-16">
                    <i class="pi pi-spinner pi-spin text-2xl text-[var(--text-color-secondary)]" />
                </div>

                <!-- Empty -->
                <div v-else-if="!documents.length" class="empty-rich m-4">
                    <div class="empty-rich__icon">
                        <i :class="hasActiveFilter ? 'pi pi-filter-slash' : 'pi pi-folder-open'" />
                    </div>
                    <div class="empty-rich__title">
                        {{ hasActiveFilter ? 'Nenhum documento encontrado' : 'Nenhum documento ainda' }}
                    </div>
                    <div class="empty-rich__sub">
                        {{ hasActiveFilter ? 'Limpe os filtros ou ajuste a busca pra ver outros resultados.' : resolvedPatientId ? 'Faça upload do primeiro laudo, receita, exame ou termo assinado deste paciente.' : 'Selecione um paciente para adicionar documentos.' }}
                    </div>
                    <Button v-if="resolvedPatientId && !hasActiveFilter" label="Enviar primeiro documento" icon="pi pi-upload" class="empty-rich__cta rounded-full" @click="uploadDlg = true" />
                </div>

                <!-- Lista -->
                <div v-else class="flex flex-col gap-2 p-3">
                    <DocumentCard v-for="doc in documents" :key="doc.id" :doc="doc" @preview="onPreview" @download="onDownload" @edit="onEdit" @delete="onDelete" @share="onShare" @sign="onSign" />
                </div>
            </div>

            <!-- Error -->
            <div v-if="error" class="p-3 rounded-md bg-red-500/5 border border-red-500/20 text-sm text-red-500">
                <i class="pi pi-exclamation-circle mr-1" /> {{ error }}
            </div>
        </div>
    </template>

    <!-- ══════════════════════════════════════════════════════════════
         Dialogs comuns (usados em ambos os modos)
       ══════════════════════════════════════════════════════════════ -->
    <DocumentUploadDialog :visible="uploadDlg" @update:visible="uploadDlg = $event" :patientId="resolvedPatientId" :patientName="patientName" :usedTags="usedTags" @uploaded="onUploaded" />

    <DocumentPreviewDialog
        :visible="previewDlg"
        @update:visible="previewDlg = $event"
        :doc="selectedDoc"
        :previewUrl="previewUrl"
        @download="onDownload"
        @edit="onEdit"
        @delete="d => { previewDlg = false; onDelete(d) }"
        @share="d => { previewDlg = false; onShare(d) }"
        @sign="d => { previewDlg = false; onSign(d) }"
    />

    <DocumentGenerateDialog :visible="generateDlg" @update:visible="generateDlg = $event" :patientId="resolvedPatientId" :patientName="patientName" @generated="onGenerated" />
    <DocumentSignatureDialog :visible="signatureDlg" @update:visible="signatureDlg = $event" :doc="selectedDoc" />
    <DocumentShareDialog :visible="shareDlg" @update:visible="shareDlg = $event" :doc="selectedDoc" />
    <ConfirmDialog />
</template>

<style scoped>
/* Empty state rico — espelha .pp-empty--rich do PatientProntuario.vue.
   Padroniza visual em ambos os modos (embedded e standalone). */
.empty-rich {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 14px;
    padding: 48px 24px;
    border: 2px dashed color-mix(in srgb, var(--primary-color) 35%, var(--surface-border));
    border-radius: 16px;
    background:
        radial-gradient(ellipse at top, color-mix(in srgb, var(--primary-color) 5%, transparent), transparent 70%),
        var(--surface-card);
    color: var(--text-color-secondary);
    text-align: center;
}
.empty-rich__icon {
    width: 72px;
    height: 72px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: color-mix(in srgb, var(--primary-color) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--primary-color) 25%, transparent);
    color: var(--primary-color);
    margin-bottom: 4px;
}
.empty-rich__icon .pi { font-size: 2rem; }
.empty-rich__title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--text-color);
    letter-spacing: -0.02em;
}
.empty-rich__sub {
    font-size: 0.82rem;
    color: var(--text-color-secondary);
    max-width: 340px;
    line-height: 1.5;
}
.empty-rich__cta {
    margin-top: 6px;
}
</style>
