<!--
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/layout/configuracoes/AuditoriaPage.vue
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
-->
<script setup>
import { ref, computed, onMounted, watch } from 'vue';
import { useToast } from 'primevue/usetoast';
import { supabase } from '@/lib/supabase/client';
import { useTenantStore } from '@/stores/tenantStore';
import { useAuditoria } from '@/composables/useAuditoria';
import { downloadAuditCSV, downloadAuditPDF, auditFormatters, sourceLabel, entityLabel } from '@/utils/auditoriaExport';
import { downloadExcel } from '@/utils/excelExport';

const toast = useToast();
const tenantStore = useTenantStore();

const { rows, filters, dateRange, loading, summary, userDisplay, load } = useAuditoria();

const tenantName = ref('');
const exportingPdf = ref(false);

// detalhes do evento clicado
const detailDialog = ref(false);
const selectedEvent = ref(null);

// ── opções dos filtros ──────────────────────────────────────────────────

const periodOptions = [
    { label: 'Hoje', value: 'today' },
    { label: 'Últimos 7 dias', value: 'last7' },
    { label: 'Últimos 30 dias', value: 'last30' },
    { label: 'Últimos 90 dias', value: 'last90' },
    { label: 'Personalizado', value: 'custom' }
];

const sourceOptions = [
    { label: 'Auditoria (CRUD)', value: 'audit_logs' },
    { label: 'Acesso a documentos', value: 'document_access_logs' },
    { label: 'Status de paciente', value: 'patient_status_history' },
    { label: 'Notificações', value: 'notification_logs' },
    { label: 'Recursos extras', value: 'addon_transactions' }
];

const entityOptions = [
    { label: 'Paciente', value: 'patients' },
    { label: 'Evento de agenda', value: 'agenda_eventos' },
    { label: 'Registro financeiro', value: 'financial_records' },
    { label: 'Documento', value: 'documents' },
    { label: 'Membro do tenant', value: 'tenant_members' },
    { label: 'Documento (acesso)', value: 'document' },
    { label: 'Notificação', value: 'notification' },
    { label: 'Status de paciente', value: 'patient_status' },
    { label: 'Transação de recurso', value: 'addon_transaction' }
];

const actionOptions = [
    { label: 'Criou', value: 'insert' },
    { label: 'Alterou', value: 'update' },
    { label: 'Excluiu', value: 'delete' },
    { label: 'Visualizou', value: 'visualizou' },
    { label: 'Baixou', value: 'baixou' },
    { label: 'Imprimiu', value: 'imprimiu' },
    { label: 'Compartilhou', value: 'compartilhou' },
    { label: 'Assinou', value: 'assinou' },
    { label: 'Status alterado', value: 'status_change' },
    { label: 'Compra', value: 'purchase' },
    { label: 'Consumo', value: 'consumption' }
];

// ── labels ─────────────────────────────────────────────────────────────

const periodLabel = computed(() => {
    const preset = periodOptions.find((p) => p.value === filters.value.periodPreset)?.label ?? '';
    const { from, to } = dateRange.value;
    const fmt = (d) => new Date(d).toLocaleDateString('pt-BR');
    return `${preset} (${fmt(from)} → ${fmt(to)})`;
});

function sourceSeverity(src) {
    const map = {
        audit_logs: 'info',
        document_access_logs: 'secondary',
        patient_status_history: 'warning',
        notification_logs: 'success',
        addon_transactions: 'help'
    };
    return map[src] || 'secondary';
}

function actionSeverity(action) {
    if (['delete', 'failed', 'bounced'].includes(action)) return 'danger';
    if (['insert', 'sent', 'delivered', 'purchase'].includes(action)) return 'success';
    if (['update', 'status_change'].includes(action)) return 'warning';
    return 'info';
}

// ── ações ──────────────────────────────────────────────────────────────

async function reload() {
    await load();
}

function openDetails(ev) {
    selectedEvent.value = ev;
    detailDialog.value = true;
}

function prettyJson(obj) {
    if (!obj) return '';
    try {
        return JSON.stringify(obj, null, 2);
    } catch {
        return String(obj);
    }
}

function slugify(s) {
    if (!s) return 'clinica';
    return (
        String(s)
            .toLowerCase()
            .normalize('NFD')
            .replace(/[\u0300-\u036f]/g, '')
            .replace(/[^a-z0-9]+/g, '-')
            .replace(/(^-|-$)/g, '')
            .slice(0, 40) || 'clinica'
    );
}

function filenameBase() {
    const now = new Date();
    const ym = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
    return `auditoria-${slugify(tenantName.value)}-${ym}`;
}

function onExportCSV() {
    try {
        downloadAuditCSV(rows.value, summary.value, periodLabel.value, userDisplay, `${filenameBase()}.csv`);
        toast.add({ severity: 'success', summary: 'CSV gerado', detail: `${summary.value.totalRows} evento(s) exportado(s).`, life: 3000 });
    } catch (err) {
        toast.add({ severity: 'error', summary: 'Falha ao gerar CSV', detail: err?.message || 'Erro inesperado', life: 5000 });
    }
}

async function onExportPDF() {
    if (exportingPdf.value) return;
    exportingPdf.value = true;
    try {
        await downloadAuditPDF(rows.value, summary.value, periodLabel.value, tenantName.value, userDisplay, `${filenameBase()}.pdf`);
        toast.add({ severity: 'success', summary: 'PDF gerado', detail: `${summary.value.totalRows} evento(s) exportado(s).`, life: 3000 });
    } catch (err) {
        toast.add({ severity: 'error', summary: 'Falha ao gerar PDF', detail: err?.message || 'Erro inesperado', life: 5000 });
    } finally {
        exportingPdf.value = false;
    }
}

async function onExportExcel() {
    try {
        await downloadExcel({
            filename: `${filenameBase()}.xlsx`,
            sheetName: 'Auditoria',
            headers: [
                { key: 'occurred_at', label: 'Data/Hora', type: 'date', width: 20 },
                { key: 'source_label', label: 'Origem', type: 'text', width: 18 },
                { key: 'entity_label', label: 'Entidade', type: 'text', width: 18 },
                { key: 'entity_id', label: 'ID entidade', type: 'text', width: 38 },
                { key: 'action', label: 'Ação', type: 'text', width: 14 },
                { key: 'description', label: 'Descrição', type: 'text', width: 60 },
                { key: 'user_display', label: 'Usuário', type: 'text', width: 24 }
            ],
            rows: rows.value.map((r) => ({
                ...r,
                source_label: sourceLabel(r.source),
                entity_label: entityLabel(r.entity_type),
                user_display: userDisplay(r.user_id)
            })),
            footerRows: [
                ['Período', periodLabel.value],
                ['Total de registros', summary.value.totalRows],
                ['Usuários distintos', summary.value.distinctUsers]
            ]
        });
        toast.add({ severity: 'success', summary: 'Excel gerado', detail: `${summary.value.totalRows} evento(s) exportado(s).`, life: 3000 });
    } catch (err) {
        toast.add({ severity: 'error', summary: 'Falha ao gerar Excel', detail: err?.message || 'Erro inesperado', life: 5000 });
    }
}

async function loadTenantName() {
    const tenantId = tenantStore.activeTenantId;
    if (!tenantId) return;
    const { data } = await supabase.from('tenants').select('name').eq('id', tenantId).maybeSingle();
    tenantName.value = data?.name || '';
}

onMounted(async () => {
    await loadTenantName();
    await reload();
});

watch(
    () => tenantStore.activeTenantId,
    async () => {
        await loadTenantName();
        await reload();
    }
);
</script>

<template>
    <div class="flex flex-col gap-5">
        <!-- Header -->
        <Card>
            <template #title>
                <div class="flex items-center gap-2">
                    <i class="pi pi-shield text-xl" />
                    Auditoria da Clínica
                </div>
            </template>
            <template #subtitle>
                Registro imutável de operações de tratamento. Exigido pela <strong>LGPD Art. 37</strong>. Use para responder solicitações do titular ou investigar inconsistências.
            </template>
        </Card>

        <!-- Filtros -->
        <Card>
            <template #content>
                <div class="grid grid-cols-1 md:grid-cols-12 gap-3">
                    <div class="md:col-span-3">
                        <label class="text-xs font-medium text-surface-500 mb-1 block">Período</label>
                        <Select v-model="filters.periodPreset" :options="periodOptions" optionLabel="label" optionValue="value" class="w-full" @change="reload" />
                    </div>

                    <div v-if="filters.periodPreset === 'custom'" class="md:col-span-4">
                        <label class="text-xs font-medium text-surface-500 mb-1 block">Intervalo personalizado</label>
                        <DatePicker v-model="filters.customRange" selectionMode="range" dateFormat="dd/mm/yy" :manualInput="false" showIcon class="w-full" @update:model-value="reload" />
                    </div>

                    <div class="md:col-span-3">
                        <label class="text-xs font-medium text-surface-500 mb-1 block">Origem</label>
                        <MultiSelect v-model="filters.sources" :options="sourceOptions" optionLabel="label" optionValue="value" placeholder="Todas" class="w-full" display="chip" :maxSelectedLabels="2" @change="reload" />
                    </div>

                    <div class="md:col-span-3">
                        <label class="text-xs font-medium text-surface-500 mb-1 block">Tipo de entidade</label>
                        <MultiSelect v-model="filters.entityTypes" :options="entityOptions" optionLabel="label" optionValue="value" placeholder="Todas" class="w-full" display="chip" :maxSelectedLabels="2" @change="reload" />
                    </div>

                    <div class="md:col-span-3">
                        <label class="text-xs font-medium text-surface-500 mb-1 block">Ação</label>
                        <MultiSelect v-model="filters.actions" :options="actionOptions" optionLabel="label" optionValue="value" placeholder="Todas" class="w-full" display="chip" :maxSelectedLabels="2" @change="reload" />
                    </div>

                    <div class="md:col-span-6">
                        <label class="text-xs font-medium text-surface-500 mb-1 block">Buscar (descrição, entidade, ação, usuário)</label>
                        <IconField>
                            <InputIcon class="pi pi-search" />
                            <InputText v-model="filters.search" placeholder="ex: paciente, login, email..." class="w-full" maxlength="120" />
                        </IconField>
                    </div>

                    <div class="md:col-span-6 flex items-end gap-2">
                        <Button label="Atualizar" icon="pi pi-refresh" severity="secondary" outlined @click="reload" :loading="loading" />
                        <Button label="Exportar CSV" icon="pi pi-file" severity="secondary" @click="onExportCSV" :disabled="!rows.length" />
                        <Button label="Exportar Excel" icon="pi pi-file-excel" severity="secondary" @click="onExportExcel" :disabled="!rows.length" />
                        <Button label="Exportar PDF" icon="pi pi-file-pdf" severity="secondary" @click="onExportPDF" :disabled="!rows.length" :loading="exportingPdf" />
                    </div>
                </div>
            </template>
        </Card>

        <!-- Resumo -->
        <div class="grid grid-cols-2 md:grid-cols-4 gap-3">
            <Card>
                <template #content>
                    <div class="flex flex-col">
                        <span class="text-xs text-surface-500 uppercase tracking-wide">Eventos no período</span>
                        <span class="text-2xl font-bold mt-1">{{ summary.totalRows }}</span>
                    </div>
                </template>
            </Card>
            <Card>
                <template #content>
                    <div class="flex flex-col">
                        <span class="text-xs text-surface-500 uppercase tracking-wide">Usuários distintos</span>
                        <span class="text-2xl font-bold mt-1">{{ summary.distinctUsers }}</span>
                    </div>
                </template>
            </Card>
            <Card>
                <template #content>
                    <div class="flex flex-col">
                        <span class="text-xs text-surface-500 uppercase tracking-wide">CRUD (criar/alterar/excluir)</span>
                        <span class="text-2xl font-bold mt-1">
                            {{ (summary.byAction.insert || 0) + (summary.byAction.update || 0) + (summary.byAction.delete || 0) }}
                        </span>
                    </div>
                </template>
            </Card>
            <Card>
                <template #content>
                    <div class="flex flex-col">
                        <span class="text-xs text-surface-500 uppercase tracking-wide">Acessos a documento</span>
                        <span class="text-2xl font-bold mt-1">{{ summary.bySource.document_access_logs || 0 }}</span>
                    </div>
                </template>
            </Card>
        </div>

        <!-- Tabela -->
        <Card>
            <template #content>
                <DataTable
                    :value="rows"
                    :loading="loading"
                    size="small"
                    stripedRows
                    paginator
                    :rows="25"
                    :rowsPerPageOptions="[10, 25, 50, 100, 200]"
                    sortField="occurred_at"
                    :sortOrder="-1"
                    emptyMessage="Nenhum evento auditado no período. Ajuste os filtros."
                    :pt="{
                        bodyRow: ({ context }) => ({ class: 'cursor-pointer hover:bg-primary/5' })
                    }"
                    @row-click="(ev) => openDetails(ev.data)"
                >
                    <Column field="occurred_at" header="Data/Hora" style="min-width: 160px" sortable>
                        <template #body="{ data }">{{ auditFormatters.fmtDate(data.occurred_at) }}</template>
                    </Column>

                    <Column field="source" header="Origem" style="width: 140px" sortable>
                        <template #body="{ data }">
                            <Tag :value="auditFormatters.sourceLabel(data.source)" :severity="sourceSeverity(data.source)" />
                        </template>
                    </Column>

                    <Column field="entity_type" header="Entidade" style="width: 130px" sortable>
                        <template #body="{ data }">{{ auditFormatters.entityLabel(data.entity_type) }}</template>
                    </Column>

                    <Column field="action" header="Ação" style="width: 120px" sortable>
                        <template #body="{ data }">
                            <Tag :value="data.action" :severity="actionSeverity(data.action)" />
                        </template>
                    </Column>

                    <Column field="description" header="Descrição">
                        <template #body="{ data }">
                            <span class="text-sm">{{ data.description || '—' }}</span>
                        </template>
                    </Column>

                    <Column field="user_id" header="Usuário" style="width: 180px">
                        <template #body="{ data }">
                            <span class="text-xs">{{ userDisplay(data.user_id) }}</span>
                        </template>
                    </Column>
                </DataTable>
            </template>
        </Card>

        <!-- Dialog de detalhes -->
        <Dialog
            v-model:visible="detailDialog"
            modal
            :draggable="false"
            :closable="true"
            :dismissableMask="true"
            maximizable
            class="dc-dialog w-[60rem]"
            :breakpoints="{ '1199px': '92vw', '768px': '96vw' }"
            header="Detalhes do evento"
        >
            <div v-if="selectedEvent" class="flex flex-col gap-3">
                <div class="grid grid-cols-1 md:grid-cols-2 gap-2 text-sm">
                    <div><strong>Data/Hora:</strong> {{ auditFormatters.fmtDate(selectedEvent.occurred_at) }}</div>
                    <div><strong>Origem:</strong> {{ auditFormatters.sourceLabel(selectedEvent.source) }}</div>
                    <div><strong>Entidade:</strong> {{ auditFormatters.entityLabel(selectedEvent.entity_type) }}</div>
                    <div><strong>Ação:</strong> {{ selectedEvent.action }}</div>
                    <div><strong>ID da entidade:</strong> <span class="font-mono text-xs">{{ selectedEvent.entity_id || '—' }}</span></div>
                    <div><strong>Usuário:</strong> {{ userDisplay(selectedEvent.user_id) }}</div>
                </div>

                <Divider />

                <div>
                    <strong class="text-sm">Descrição:</strong>
                    <p class="text-sm mt-1">{{ selectedEvent.description }}</p>
                </div>

                <div v-if="selectedEvent.details && selectedEvent.details.changed_fields?.length">
                    <strong class="text-sm">Campos alterados:</strong>
                    <div class="flex flex-wrap gap-1 mt-1">
                        <Tag v-for="f in selectedEvent.details.changed_fields" :key="f" :value="f" severity="warning" />
                    </div>
                </div>

                <div v-if="selectedEvent.details?.old_values">
                    <strong class="text-sm">Estado anterior:</strong>
                    <pre class="text-xs bg-surface-50 p-2 rounded border border-surface-200 overflow-auto max-h-64 mt-1">{{ prettyJson(selectedEvent.details.old_values) }}</pre>
                </div>

                <div v-if="selectedEvent.details?.new_values">
                    <strong class="text-sm">Estado novo:</strong>
                    <pre class="text-xs bg-surface-50 p-2 rounded border border-surface-200 overflow-auto max-h-64 mt-1">{{ prettyJson(selectedEvent.details.new_values) }}</pre>
                </div>

                <div v-if="selectedEvent.details && !selectedEvent.details.old_values && !selectedEvent.details.new_values">
                    <strong class="text-sm">Metadados:</strong>
                    <pre class="text-xs bg-surface-50 p-2 rounded border border-surface-200 overflow-auto max-h-64 mt-1">{{ prettyJson(selectedEvent.details) }}</pre>
                </div>
            </div>

            <template #footer>
                <Button label="Fechar" icon="pi pi-times" text @click="detailDialog = false" />
            </template>
        </Dialog>
    </div>
</template>
