<template>
  <!-- Échafaudage commun des pages de rapports : en-tête + tuiles stats + graphique + états (chargement/erreur/vide) + tableau responsive.
       La page fournit : filtres (#filters), cartes (:cards), colonnes (:columns), lignes (:rows) et un fetch qui pilote :loading/:error/:has-run.
       Les slots body-cell-* / #item sont transmis au DataTable. Voir composables/useCsvExport pour @export. -->
  <q-page padding>
    <PageHeader :title="title" :back="back">
      <template #actions>
        <q-input v-if="searchable" v-model="search" dense outlined placeholder="Filtrer…" clearable class="rs-search">
          <template #prepend><q-icon name="search" /></template>
        </q-input>
        <slot name="actions" />
        <q-btn v-if="exportable && rows && rows.length" flat dense no-caps icon="download" label="CSV" @click="$emit('export')">
          <q-tooltip>Exporter en CSV</q-tooltip>
        </q-btn>
      </template>
      <template v-if="$slots.filters" #filters><slot name="filters" /></template>
    </PageHeader>

    <div v-if="cards && cards.length" class="row q-col-gutter-sm q-mb-md">
      <div v-for="(c, i) in cards" :key="i" class="col-6 col-sm">
        <StatCard :label="c.label" :value="c.value" :icon="c.icon" :color="c.color || 'primary'" :value-class="c.valueClass" :hint="c.hint" />
      </div>
    </div>

    <slot name="chart" />

    <TableSkeleton v-if="loading" :rows="8" :cols="(columns && columns.length) || 5" />
    <div v-else-if="error" class="rs-state">
      <q-icon name="error_outline" size="34px" color="negative" />
      <div>{{ error }}</div>
      <q-btn outline no-caps color="primary" label="Réessayer" @click="$emit('retry')" />
    </div>
    <EmptyState v-else-if="!rows || !rows.length"
      :icon="hasRun ? 'inbox' : 'filter_alt'"
      :label="hasRun ? empty : 'Choisissez une période, puis « Générer ».'" />
    <DataTable v-else :rows="rows" :columns="columns" :row-key="rowKey" :pagination="pagination" :filter="searchable ? search : undefined">
      <template v-for="name in tableSlotNames" #[name]="sp"><slot :name="name" v-bind="sp || {}" /></template>
    </DataTable>

    <!-- Contenu additionnel sous le tableau (ex. résumé de période) — la page gère sa propre visibilité. -->
    <div v-if="$slots.below && !loading && !error"><slot name="below" /></div>
  </q-page>
</template>

<script setup>
import { useSlots, computed, ref } from 'vue'
import PageHeader from './PageHeader.vue'
import StatCard from './StatCard.vue'
import DataTable from './DataTable.vue'
import TableSkeleton from './TableSkeleton.vue'
import EmptyState from './EmptyState.vue'

defineProps({
  title: { type: String, default: '' },
  back: { type: [String, Object], default: '/rapports' },
  loading: { type: Boolean, default: false },
  error: { type: String, default: '' },
  hasRun: { type: Boolean, default: true },
  cards: { type: Array, default: () => [] },
  columns: { type: Array, default: () => [] },
  rows: { type: Array, default: () => [] },
  rowKey: { type: String, default: 'name' },
  pagination: { type: Object, default: () => ({ rowsPerPage: 50 }) },
  empty: { type: String, default: 'Aucune donnée pour cette période.' },
  exportable: { type: Boolean, default: true },
  searchable: { type: Boolean, default: false },
})
defineEmits(['retry', 'export'])

const search = ref('')
const slots = useSlots()
const RESERVED = ['filters', 'chart', 'actions', 'below']
const tableSlotNames = computed(() => Object.keys(slots).filter(n => !RESERVED.includes(n)))
</script>

<style scoped>
.rs-state { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 40px 20px; text-align: center; color: var(--ops-text-muted); }
.rs-search { width: 200px; max-width: 100%; }
</style>
