<template>
  <div class="space-y-4">
    <!-- Toolbar + counter row -->
    <div
      v-if="$slots.toolbar || showCounter || showPerPage"
      class="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between"
    >
      <div class="flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
        <slot name="toolbar" />
      </div>

      <div class="flex items-center gap-3">
        <div v-if="showPerPage && pagination?.perPageOptions?.length" class="flex items-center gap-2">
          <label
            class="text-xs font-semibold uppercase tracking-wide text-base-content/70"
            for="dt-per-page"
          >
            Par page
          </label>
          <select
            id="dt-per-page"
            :value="pagination.perPage"
            class="select select-bordered select-sm"
            @change="emit('update:perPage', Number(($event.target as HTMLSelectElement).value))"
          >
            <option v-for="opt in pagination.perPageOptions" :key="opt" :value="opt">
              {{ opt }}
            </option>
          </select>
        </div>

        <p v-if="showCounter && pagination" class="text-xs text-base-content/50 whitespace-nowrap">
          {{ pagination.pageItems }} / {{ pagination.totalItems }}
          résultat{{ pagination.totalItems > 1 ? 's' : '' }}
        </p>
      </div>
    </div>

    <!-- Loading state (full spinner only when no filterable columns to keep visible) -->
    <div v-if="loading && !hasFilterableColumns" class="flex justify-center py-8">
      <slot name="loading">
        <span class="loading loading-spinner" aria-hidden="true" />
      </slot>
    </div>

    <!-- Empty state (no data at all, no filterable columns to keep visible) -->
    <template v-else-if="isEmpty && !hasFilterableColumns">
      <slot name="empty">
        <p class="text-sm text-base-content/70 py-8 text-center">
          {{ emptyMessage }}
        </p>
      </slot>
    </template>

    <!-- No results without filterable columns -->
    <template v-else-if="rows.length === 0 && !hasFilterableColumns">
      <slot name="no-results">
        <p class="text-sm text-base-content/70 py-8 text-center">
          {{ noResultsMessage }}
        </p>
      </slot>
    </template>

    <!-- Table (always shown when there are filterable columns, even during loading or with 0 rows) -->
    <template v-else>
      <div class="overflow-x-auto overflow-y-clip relative">
        <!-- Loading overlay (keeps table & filter inputs visible) -->
        <div
          v-if="loading && hasFilterableColumns"
          class="absolute inset-0 bg-base-100/50 z-10 flex items-center justify-center"
        >
          <span class="loading loading-spinner" aria-hidden="true" />
        </div>
        <table :class="['table table-sm md:table-md', tableClass]">
          <thead>
            <!-- Header labels + sort -->
            <tr>
              <th
                v-for="col in columns"
                :key="col.key"
                :class="[
                  col.width,
                  col.class,
                  col.headerClass,
                  alignClass(col),
                  { 'hidden sm:table-cell': col.hiddenMobile },
                ]"
              >
                <slot :name="`header-${col.key}`" :column="col">
                  <span
                    :class="[
                      'inline-flex items-center gap-1',
                      col.sortable ? 'cursor-pointer select-none hover:text-base-content' : '',
                    ]"
                    @click="col.sortable && handleHeaderSort(col)"
                  >
                    {{ col.label }}
                    <template v-if="col.sortable">
                      <IconLucideChevronUp
                        v-if="isSortedAsc(col)"
                        class="h-3.5 w-3.5"
                        aria-label="Trié croissant"
                      />
                      <IconLucideChevronDown
                        v-else-if="isSortedDesc(col)"
                        class="h-3.5 w-3.5"
                        aria-label="Trié décroissant"
                      />
                      <IconLucideChevronsUpDown
                        v-else
                        class="h-3.5 w-3.5 opacity-30"
                        aria-label="Triable"
                      />
                    </template>
                  </span>
                </slot>
              </th>
              <th v-if="expandable" class="w-12" />
            </tr>
            <!-- Filter inputs row -->
            <tr v-if="hasFilterableColumns">
              <th
                v-for="col in columns"
                :key="`filter-${col.key}`"
                class="p-1"
                :class="{ 'hidden sm:table-cell': col.hiddenMobile }"
              >
                <input
                  v-if="col.filterable"
                  type="text"
                  class="input input-bordered input-xs w-full"
                  :placeholder="col.filterPlaceholder || 'Filtrer…'"
                  :value="columnFilters[col.key] ?? ''"
                  @input="handleFilterInput(col.key, ($event.target as HTMLInputElement).value)"
                />
              </th>
              <th v-if="expandable" />
            </tr>
          </thead>
          <tbody>
            <!-- No results message (inside table to keep headers visible) -->
            <tr v-if="rows.length === 0">
              <td :colspan="expandable ? columns.length + 1 : columns.length" class="text-center py-8">
                <p class="text-sm text-base-content/70">
                  {{ isEmpty ? emptyMessage : noResultsMessage }}
                </p>
              </td>
            </tr>
            <template v-for="(row, idx) in rows" :key="getRowKey(row)">
              <tr>
                <td
                  v-for="col in columns"
                  :key="col.key"
                  :class="[
                    col.class,
                    alignClass(col),
                    { 'hidden sm:table-cell': col.hiddenMobile },
                  ]"
                >
                  <slot :name="`cell-${col.key}`" :row="row" :column="col" :index="idx">
                    {{ row[col.key] ?? '—' }}
                  </slot>
                </td>
                <td v-if="expandable" class="text-center">
                  <button
                    v-if="!canExpand || canExpand(row)"
                    type="button"
                    class="btn btn-ghost btn-xs"
                    @click="emit('toggle-expand', getRowKey(row))"
                  >
                    {{ isExpanded(row) ? 'Masquer' : 'Voir' }}
                  </button>
                  <span v-else class="text-xs text-base-content/50">—</span>
                </td>
              </tr>
              <!-- Expanded row -->
              <tr v-if="expandable && isExpanded(row)">
                <td :colspan="columns.length + 1" class="bg-base-200/50 p-4">
                  <slot name="row-expanded" :row="row" :index="idx" />
                </td>
              </tr>
            </template>
          </tbody>
        </table>
      </div>

      <!-- Pagination -->
      <Pagination
        v-if="pagination && pagination.totalPages > 1"
        :current-page="pagination.currentPage"
        :total-pages="pagination.totalPages"
        @update:current-page="emit('update:currentPage', $event)"
      />
    </template>

    <slot name="footer" />
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import type { DataTableColumn, DataTableSort, DataTablePagination, DataTableColumnFilters } from '~/shared/types/dataTable'
import Pagination from '~/components/common/Pagination.vue'
import IconLucideChevronUp from '~icons/lucide/chevron-up'
import IconLucideChevronDown from '~icons/lucide/chevron-down'
import IconLucideChevronsUpDown from '~icons/lucide/chevrons-up-down'

const props = withDefaults(defineProps<{
  columns: DataTableColumn[]
  rows: any[]
  rowKey?: string
  loading?: boolean
  sort?: DataTableSort | null
  pagination?: DataTablePagination | null
  columnFilters?: DataTableColumnFilters
  emptyMessage?: string
  noResultsMessage?: string
  expandable?: boolean
  expandedKeys?: Set<string>
  canExpand?: (row: any) => boolean
  tableClass?: string
  showCounter?: boolean
  showPerPage?: boolean
}>(), {
  rowKey: 'id',
  loading: false,
  sort: null,
  pagination: null,
  columnFilters: () => ({}),
  emptyMessage: 'Aucune donnée disponible.',
  noResultsMessage: 'Aucun résultat ne correspond à vos critères.',
  expandable: false,
  expandedKeys: () => new Set<string>(),
  canExpand: undefined,
  tableClass: '',
  showCounter: true,
  showPerPage: false,
})

const emit = defineEmits<{
  (e: 'sort', sort: DataTableSort): void
  (e: 'update:currentPage', page: number): void
  (e: 'update:perPage', perPage: number): void
  (e: 'update:columnFilters', filters: DataTableColumnFilters): void
  (e: 'toggle-expand', key: string): void
}>()

const hasFilterableColumns = computed(() =>
  props.columns.some(col => col.filterable),
)

const isEmpty = computed(() => {
  if (props.pagination) {
    return props.pagination.totalItems === 0
  }
  return props.rows.length === 0
})

const getRowKey = (row: any): string => {
  return String(row[props.rowKey] ?? '')
}

const isExpanded = (row: any): boolean => {
  return props.expandedKeys?.has(getRowKey(row)) ?? false
}

const sortKeyForColumn = (col: DataTableColumn): string => {
  return col.sortKey ?? col.key
}

const isSortedAsc = (col: DataTableColumn): boolean => {
  return props.sort?.field === sortKeyForColumn(col) && props.sort?.direction === 'asc'
}

const isSortedDesc = (col: DataTableColumn): boolean => {
  return props.sort?.field === sortKeyForColumn(col) && props.sort?.direction === 'desc'
}

const handleHeaderSort = (col: DataTableColumn) => {
  const key = sortKeyForColumn(col)
  const currentDirection = props.sort?.field === key ? props.sort.direction : null

  emit('sort', {
    field: key,
    direction: currentDirection === 'asc' ? 'desc' : 'asc',
  })
}

let filterDebounceTimer: ReturnType<typeof setTimeout> | null = null

const handleFilterInput = (key: string, value: string) => {
  if (filterDebounceTimer) clearTimeout(filterDebounceTimer)
  filterDebounceTimer = setTimeout(() => {
    const updated = { ...props.columnFilters, [key]: value }
    // Remove empty filter keys
    for (const k of Object.keys(updated)) {
      if (!updated[k]) delete updated[k]
    }
    emit('update:columnFilters', updated)
  }, 300)
}

const alignClass = (col: DataTableColumn): string => {
  if (col.align === 'center') return 'text-center'
  if (col.align === 'right') return 'text-right'
  return ''
}
</script>
