<template>
  <div :id="componentId" class="w-full" v-bind="attrs">
    <table :class="twMerge('w-full border-separate border-spacing-0 border border-black rounded-malio overflow-hidden', tableClass)">
      <thead>
        <tr class="bg-m-surface">
          <th
            v-for="col in columns"
            :key="col.key"
            scope="col"
            class="border-b border-black px-3 py-3 text-left align-middle text-[16px]"
          >
            <slot
              v-if="$slots[`header-${col.key}`]"
              :name="`header-${col.key}`"
              :column="col"
            />
            <span v-else class="font-semibold text-black">{{ col.label }}</span>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="(item, index) in items"
          :key="index"
          :class="rowClickable ? 'cursor-pointer hover:bg-m-bg' : ''"
          :tabindex="rowClickable ? 0 : undefined"
          data-test="row"
          @click="rowClickable ? emit('row-click', item) : undefined"
          @keydown.enter="rowClickable ? emit('row-click', item) : undefined"
          @keydown.space.prevent="rowClickable ? emit('row-click', item) : undefined"
        >
          <td
            v-for="col in columns"
            :key="col.key"
            class="px-3 py-4 text-[14px] text-black"
            :class="index < items.length - 1 ? 'border-b border-black' : ''"
          >
            <slot
              v-if="$slots[`cell-${col.key}`]"
              :name="`cell-${col.key}`"
              :item="item"
              :column="col"
            />
            <template v-else>{{ item[col.key] }}</template>
          </td>
        </tr>
        <tr v-if="!items.length" data-test="empty-row">
          <td
            :colspan="columns.length"
            class="px-3 py-4 text-center text-m-muted"
          >
            <slot name="empty">{{ emptyMessage }}</slot>
          </td>
        </tr>
      </tbody>
    </table>

    <div
      v-if="totalItems > 0"
      class="flex items-center justify-between pt-3"
      data-test="pagination"
    >
      <div class="flex items-center gap-4">
        <span class="whitespace-nowrap text-[16px] text-black">Lignes :</span>
        <div class="h-[30px]">
          <MalioSelect
            :model-value="perPage"
            :options="perPageSelectOptions"
            group-class="w-20 h-[30px]"
            field-class="h-[30px]"
            rounded="rounded"
            text-field="text-sm"
            text-value="text-sm"
            text-label="text-xs"
            data-test="per-page-select"
            @update:model-value="onPerPageChange"
          />
        </div>
      </div>

      <nav aria-label="Pagination" class="flex items-center gap-1" data-test="pagination-nav">
        <MalioButton
          variant="tertiary"
          label="Préc."
          :disabled="page <= 1"
          button-class="h-[30px] w-auto min-w-0 px-3 text-sm"
          aria-label="Page précédente"
          data-test="prev-button"
          @click="goToPage(page - 1)"
        />

        <template v-for="(p, idx) in visiblePages" :key="idx">
          <span
            v-if="p === '...'"
            class="px-1 text-sm text-m-muted"
            aria-hidden="true"
          >…</span>
          <button
            v-else
            type="button"
            class="inline-flex h-[30px] min-w-[2.5rem] items-center justify-center rounded px-2 text-sm transition-colors"
            :class="p === page
              ? 'bg-m-btn-primary text-white font-semibold'
              : 'text-m-text hover:bg-m-bg'"
            :aria-current="p === page ? 'page' : undefined"
            :data-test="`page-${p}`"
            @click="goToPage(p)"
          >
            {{ p }}
          </button>
        </template>

        <MalioButton
          variant="tertiary"
          label="Suiv."
          :disabled="page >= totalPages"
          button-class="h-[30px] w-auto min-w-0 px-3 text-sm"
          aria-label="Page suivante"
          data-test="next-button"
          @click="goToPage(page + 1)"
        />
      </nav>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, useAttrs, useId } from 'vue'
import { twMerge } from 'tailwind-merge'
import MalioSelect from '../select/Select.vue'
import MalioButton from '../button/Button.vue'

defineOptions({ name: 'MalioDataTable', inheritAttrs: false })

type DataTableColumn = {
  key: string
  label: string
}

const attrs = useAttrs()

const props = withDefaults(
  defineProps<{
    id?: string
    columns: DataTableColumn[]
    items: Record<string, unknown>[]
    totalItems: number
    page?: number
    perPage?: number
    perPageOptions?: number[]
    rowClickable?: boolean
    tableClass?: string
    emptyMessage?: string
  }>(),
  {
    id: '',
    page: 1,
    perPage: 10,
    perPageOptions: () => [10, 25, 50],
    rowClickable: true,
    tableClass: '',
    emptyMessage: 'Aucune donnée',
  },
)

const emit = defineEmits<{
  (e: 'update:page' | 'update:per-page', value: number): void
  (e: 'row-click', item: Record<string, unknown>): void
}>()

const generatedId = useId()
const componentId = computed(() => props.id || `malio-datatable-${generatedId}`)

const totalPages = computed(() => Math.max(1, Math.ceil(props.totalItems / props.perPage)))

const perPageSelectOptions = computed(() =>
  props.perPageOptions.map(n => ({ label: String(n), value: n }))
)

function onPerPageChange(value: string | number | null) {
  if (value !== null) {
    emit('update:per-page', Number(value))
    emit('update:page', 1)
  }
}

function goToPage(page: number) {
  if (page >= 1 && page <= totalPages.value) {
    emit('update:page', page)
  }
}

const visiblePages = computed(() => {
  const total = totalPages.value
  const current = props.page

  if (total <= 5) {
    return Array.from({ length: total }, (_, i) => i + 1)
  }

  const pages: (number | '...')[] = []
  pages.push(1)

  if (current > 3) {
    pages.push('...')
  }

  const start = Math.max(2, current - 1)
  const end = Math.min(total - 1, current + 1)

  for (let i = start; i <= end; i++) {
    pages.push(i)
  }

  if (current < total - 2) {
    pages.push('...')
  }

  if (total > 1) {
    pages.push(total)
  }

  return pages
})
</script>
