<script setup>
import { ref, watch, computed } from "vue";
import { router } from "@inertiajs/vue3";
import SkeletonTable from "@/Components/Skeleton/SkeletonTable.vue";
import EmptyState from "@/Components/EmptyState.vue";
import {
  Table,
  TableHeader,
  TableHead,
  TableBody,
  TableRow,
  TableCell,
} from "@/Components/ui/table";

const props = defineProps({
  columns: { type: Array, required: true }, // [{ key, label, sortable?, align?, class? }]
  rows: { type: Array, default: () => [] },
  meta: { type: Object, required: true }, // { current_page, per_page, total, last_page }
  sort: { type: Object, default: () => ({ key: null, direction: null }) },
  search: { type: String, default: "" },
  page: { type: Number, default: 1 },
  pageSize: { type: Number, default: 10 },
  pageSizeOptions: { type: Array, default: () => [10, 25, 50] },
  routeName: { type: String, required: true },
  routeParams: { type: Object, default: () => ({}) },
  query: { type: Object, default: () => ({}) },
  preserveState: { type: Boolean, default: true },
  preserveScroll: { type: Boolean, default: true },
  loading: { type: Boolean, default: false },
  emptyText: { type: String, default: "Ni podatkov." },
  rowKey: { type: [String, Function], default: "id" },
  showToolbar: { type: Boolean, default: true },
  onlyProps: { type: Array, default: () => [] }, // e.g., ['contracts']
  // Pagination UX options
  showPageStats: { type: Boolean, default: true },
  showGoto: { type: Boolean, default: true },
  maxPageLinks: { type: Number, default: 5 }, // odd number preferred
  // Optional custom page parameter name (Laravel custom paginator key, e.g. 'client-cases-page')
  pageParamName: { type: String, default: "page" },
});

const emit = defineEmits([
  "update:sort",
  "update:search",
  "update:page",
  "update:pageSize",
  "row:click",
]);

const internalSearch = ref(props.search);
watch(
  () => props.search,
  (v) => {
    internalSearch.value = v ?? "";
  }
);

let searchTimer;
watch(internalSearch, (v) => {
  emit("update:search", v);
  // Debounced request, reset page to 1
  clearTimeout(searchTimer);
  searchTimer = setTimeout(() => doRequest({ page: 1, search: v }), 300);
});

function keyOf(row) {
  if (typeof props.rowKey === "function") return props.rowKey(row);
  if (typeof props.rowKey === "string" && row && row[props.rowKey] != null)
    return row[props.rowKey];
  return row?.uuid ?? row?.id ?? Math.random().toString(36).slice(2);
}

function toggleSort(col) {
  if (!col?.sortable) return;
  const { key } = col;
  const current = props.sort || { key: null, direction: null };
  let direction = "asc";
  if (current.key === key) {
    direction =
      current.direction === "asc" ? "desc" : current.direction === "desc" ? null : "asc";
  }
  emit("update:sort", { key: direction ? key : null, direction });
  doRequest({ sort: direction ? key : null, direction, page: 1 });
}

function setPage(p) {
  emit("update:page", p);
  doRequest({ page: p });
}
function setPageSize(ps) {
  const perPage = Number(ps);
  emit("update:pageSize", perPage);
  doRequest({ page: 1, perPage });
}

function doRequest(overrides = {}) {
  const q = {
    ...props.query,
    // Laravel expects snake_case per_page
    per_page: overrides.perPage ?? props.meta?.per_page ?? props.pageSize ?? 10,
    sort: overrides.sort ?? props.sort?.key ?? null,
    direction: overrides.direction ?? props.sort?.direction ?? null,
    search: overrides.search ?? props.search ?? "",
  };
  const pageParam = props.pageParamName || "page";
  q[pageParam] = overrides.page ?? props.meta?.current_page ?? props.page ?? 1;
  if (pageParam !== "page") {
    delete q.page;
  }
  // Clean nulls
  Object.keys(q).forEach((k) => {
    if (q[k] === null || q[k] === undefined || q[k] === "") delete q[k];
  });
  const url = route(props.routeName, props.routeParams || {});
  router.get(url, q, {
    preserveScroll: props.preserveScroll,
    preserveState: props.preserveState,
    replace: true,
    only: props.onlyProps.length ? props.onlyProps : undefined,
  });
}

const total = computed(() => props.meta?.total ?? 0);
const currentPage = computed(() => props.meta?.current_page ?? 1);
const lastPage = computed(() => props.meta?.last_page ?? 1);
const perPage = computed(() => props.meta?.per_page ?? props.pageSize ?? 10);

// Ensure the page-size selector always contains the current server value
const pageSizeOptionsResolved = computed(() => {
  const base = Array.isArray(props.pageSizeOptions)
    ? [...props.pageSizeOptions]
    : [10, 25, 50];
  const current = perPage.value;
  if (current && !base.includes(current)) {
    base.push(current);
  }
  return base.sort((a, b) => a - b);
});

const showingFrom = computed(() => {
  if (total.value === 0) return 0;
  return (currentPage.value - 1) * perPage.value + 1;
});
const showingTo = computed(() => {
  if (total.value === 0) return 0;
  return Math.min(currentPage.value * perPage.value, total.value);
});

const gotoInput = ref("");

const visiblePages = computed(() => {
  const pages = [];
  const count = lastPage.value;
  if (count <= 1) return [1];
  const windowSize = Math.max(3, props.maxPageLinks);
  const half = Math.floor(windowSize / 2);
  let start = Math.max(1, currentPage.value - half);
  let end = Math.min(count, start + windowSize - 1);
  // Adjust start if at the end
  start = Math.max(1, Math.min(start, end - windowSize + 1));
  for (let p = start; p <= end; p++) pages.push(p);
  return pages;
});

function goToPageInput() {
  const raw = String(gotoInput.value || "").trim();
  const n = Number(raw);
  if (!Number.isFinite(n)) return;
  const target = Math.max(1, Math.min(lastPage.value, Math.floor(n)));
  if (target !== currentPage.value) setPage(target);
  gotoInput.value = "";
}
</script>

<template>
  <div class="w-full">
    <div v-if="showToolbar" class="mb-3 flex items-center gap-3">
      <div class="flex items-center gap-2">
        <input
          type="text"
          class="w-64 rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 text-sm"
          placeholder="Iskanje..."
          v-model="internalSearch"
        />
      </div>
      <slot name="toolbar-extra" />
      <div class="ml-auto flex items-center gap-2">
        <label class="text-sm text-gray-600">Na stran</label>
        <select
          class="rounded border-gray-300 text-sm"
          :value="meta?.per_page || pageSize"
          @change="setPageSize($event.target.value)"
        >
          <option v-for="opt in pageSizeOptionsResolved" :key="opt" :value="opt">
            {{ opt }}
          </option>
        </select>
      </div>
    </div>

    <div
      class="relative overflow-x-auto rounded-lg border border-gray-200 bg-white shadow-sm"
    >
      <Table class="text-sm">
        <TableHeader
          class="sticky top-0 z-10 bg-gray-50/90 backdrop-blur border-b border-gray-200 shadow-sm"
        >
          <TableRow class="border-b">
            <TableHead v-for="col in columns" :key="col.key" :class="col.class">
              <button
                v-if="col.sortable"
                type="button"
                class="inline-flex items-center gap-1 hover:text-indigo-600"
                @click="toggleSort(col)"
                :aria-sort="sort?.key === col.key ? sort.direction || 'none' : 'none'"
              >
                <span class="uppercase">{{ col.label }}</span>
                <span v-if="sort?.key === col.key && sort.direction === 'asc'">▲</span>
                <span v-else-if="sort?.key === col.key && sort.direction === 'desc'"
                  >▼</span
                >
              </button>
              <span v-else>{{ col.label }}</span>
            </TableHead>
            <TableHead v-if="$slots.actions" class="w-px">&nbsp;</TableHead>
          </TableRow>
        </TableHeader>

        <TableBody>
          <template v-if="!loading && rows.length">
            <TableRow
              v-for="(row, idx) in rows"
              :key="keyOf(row)"
              @click="$emit('row:click', row)"
              class="cursor-default hover:bg-gray-50/50"
            >
              <TableCell
                v-for="col in columns"
                :key="col.key"
                :class="col.class"
              >
                <template v-if="$slots['cell-' + col.key]">
                  <slot
                    :name="'cell-' + col.key"
                    :row="row"
                    :column="col"
                    :value="row?.[col.key]"
                    :index="idx"
                  />
                </template>
                <template v-else-if="$slots.cell">
                  <slot
                    name="cell"
                    :row="row"
                    :column="col"
                    :value="row?.[col.key]"
                    :index="idx"
                  />
                </template>
                <template v-else>
                  {{ row?.[col.key] ?? "" }}
                </template>
              </TableCell>
              <TableCell v-if="$slots.actions" class="w-px text-right">
                <slot name="actions" :row="row" :index="idx" />
              </TableCell>
            </TableRow>
          </template>
          <template v-else-if="loading">
            <TableRow>
              <TableCell :colspan="columns.length + ($slots.actions ? 1 : 0)">
                <SkeletonTable :rows="5" :cols="columns.length" />
              </TableCell>
            </TableRow>
          </template>
          <template v-else>
            <TableRow>
              <TableCell :colspan="columns.length + ($slots.actions ? 1 : 0)">
                <slot name="empty">
                  <div class="p-6 text-center text-gray-500">{{ emptyText }}</div>
                </slot>
              </TableCell>
            </TableRow>
          </template>
        </TableBody>
      </Table>
    </div>

    <nav
      class="mt-3 flex flex-wrap items-center justify-between gap-3 text-sm text-gray-700"
      aria-label="Pagination"
    >
      <div v-if="showPageStats">
        <span v-if="total > 0"
          >Prikazano: {{ showingFrom }}–{{ showingTo }} od {{ total }}</span
        >
        <span v-else>Ni zadetkov</span>
      </div>
      <div class="flex items-center gap-1">
        <!-- First -->
        <button
          class="px-2 py-1 rounded border border-gray-300 hover:bg-gray-50 disabled:opacity-50"
          :disabled="currentPage <= 1"
          @click="setPage(1)"
          aria-label="Prva stran"
        >
          ««
        </button>
        <!-- Prev -->
        <button
          class="px-2 py-1 rounded border border-gray-300 hover:bg-gray-50 disabled:opacity-50"
          :disabled="currentPage <= 1"
          @click="setPage(currentPage - 1)"
          aria-label="Prejšnja stran"
        >
          «
        </button>

        <!-- Leading ellipsis / first page when window doesn't include 1 -->
        <button
          v-if="visiblePages[0] > 1"
          class="px-2 py-1 rounded border border-gray-300 hover:bg-gray-50"
          @click="setPage(1)"
        >
          1
        </button>
        <span v-if="visiblePages[0] > 2" class="px-1">…</span>

        <!-- Page numbers -->
        <button
          v-for="p in visiblePages"
          :key="p"
          class="px-3 py-1 rounded border transition-colors"
          :class="
            p === currentPage
              ? 'border-indigo-600 bg-indigo-600 text-white'
              : 'border-gray-300 hover:bg-gray-50'
          "
          :aria-current="p === currentPage ? 'page' : undefined"
          @click="setPage(p)"
        >
          {{ p }}
        </button>

        <!-- Trailing ellipsis / last page when window doesn't include last -->
        <span v-if="visiblePages[visiblePages.length - 1] < lastPage - 1" class="px-1"
          >…</span
        >
        <button
          v-if="visiblePages[visiblePages.length - 1] < lastPage"
          class="px-2 py-1 rounded border border-gray-300 hover:bg-gray-50"
          @click="setPage(lastPage)"
        >
          {{ lastPage }}
        </button>

        <!-- Next -->
        <button
          class="px-2 py-1 rounded border border-gray-300 hover:bg-gray-50 disabled:opacity-50"
          :disabled="currentPage >= lastPage"
          @click="setPage(currentPage + 1)"
          aria-label="Naslednja stran"
        >
          »
        </button>
        <!-- Last -->
        <button
          class="px-2 py-1 rounded border border-gray-300 hover:bg-gray-50 disabled:opacity-50"
          :disabled="currentPage >= lastPage"
          @click="setPage(lastPage)"
          aria-label="Zadnja stran"
        >
          »»
        </button>

        <!-- Goto page -->
        <div v-if="showGoto" class="ms-2 flex items-center gap-1">
          <input
            v-model="gotoInput"
            type="number"
            min="1"
            :max="lastPage"
            inputmode="numeric"
            class="w-16 rounded border-gray-300 focus:border-indigo-500 focus:ring-indigo-500 text-sm"
            :placeholder="String(currentPage)"
            aria-label="Pojdi na stran"
            @keyup.enter="goToPageInput"
            @blur="goToPageInput"
          />
          <span class="text-gray-500">/ {{ lastPage }}</span>
        </div>
      </div>
    </nav>
  </div>
</template>
