<script setup>
import { computed, ref, watch } from "vue";
import SkeletonTable from "@/Components/Skeleton/SkeletonTable.vue";
import EmptyState from "@/Components/EmptyState.vue";
import DataTablePaginationClient from "@/Components/DataTable/DataTablePaginationClient.vue";
import {
  Table,
  TableHeader,
  TableHead,
  TableBody,
  TableRow,
  TableCell,
} from "@/Components/ui/table";
import { Button } from "../ui/button";
import { ArrowDownNarrowWide, ArrowUpWideNarrowIcon } from "lucide-vue-next";

const props = defineProps({
  columns: { type: Array, required: true }, // [{ key, label, sortable?, align?, class?, formatter? }]
  rows: { type: Array, default: () => [] },
  // Sorting
  sort: { type: Object, default: () => ({ key: null, direction: null }) },
  // Searching
  search: { type: String, default: "" },
  searchKeys: { type: [Array, Function], default: () => [] },
  // Pagination
  page: { type: Number, default: 1 },
  pageSize: { type: Number, default: 10 },
  pageSizeOptions: { type: Array, default: () => [10, 25, 50] },
  // UI
  loading: { type: Boolean, default: false },
  emptyText: { type: String, default: "Ni podatkov." },
  rowKey: { type: [String, Function], default: "id" },
  showToolbar: { type: Boolean, default: true },
  // Pagination UX options
  showPagination: { type: Boolean, default: true },
  showPageStats: { type: Boolean, default: true },
  showGoto: { type: Boolean, default: true },
  maxPageLinks: { type: Number, default: 5 }, // odd number preferred
});

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 ?? "";
  }
);
watch(internalSearch, (v, ov) => {
  if (v !== props.search) {
    emit("update:search", v);
    // reset page when search changes
    if (props.page !== 1) emit("update:page", 1);
  }
});

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 });
  // reset to page 1 when sort changes
  if (props.page !== 1) emit("update:page", 1);
}

const filteredRows = computed(() => {
  const s = (props.search ?? "").toString().trim().toLowerCase();
  if (!s) return props.rows || [];
  const keys = props.searchKeys;
  if (typeof keys === "function") {
    return (props.rows || []).filter((r) => {
      try {
        return String(keys(r) ?? "")
          .toLowerCase()
          .includes(s);
      } catch (e) {
        return false;
      }
    });
  }
  const arr =
    Array.isArray(keys) && keys.length ? keys : Object.keys(props.rows?.[0] || {});
  return (props.rows || []).filter((r) => {
    return arr.some((k) =>
      String(r?.[k] ?? "")
        .toLowerCase()
        .includes(s)
    );
  });
});

const sortedRows = computed(() => {
  const { key, direction } = props.sort || { key: null, direction: null };
  if (!key || !direction) return filteredRows.value;
  const arr = [...filteredRows.value];
  arr.sort((a, b) => {
    const av = a?.[key];
    const bv = b?.[key];
    if (av == null && bv == null) return 0;
    if (av == null) return direction === "asc" ? -1 : 1;
    if (bv == null) return direction === "asc" ? 1 : -1;
    if (typeof av === "number" && typeof bv === "number")
      return direction === "asc" ? av - bv : bv - av;
    return direction === "asc"
      ? String(av).localeCompare(String(bv))
      : String(bv).localeCompare(String(av));
  });
  return arr;
});

const total = computed(() => sortedRows.value.length);
const lastPage = computed(() =>
  Math.max(1, Math.ceil(total.value / (props.pageSize || 10)))
);
const currentPage = computed(() =>
  Math.min(Math.max(1, props.page || 1), lastPage.value)
);
const startIndex = computed(() => (currentPage.value - 1) * (props.pageSize || 10));
const endIndex = computed(() =>
  Math.min(startIndex.value + (props.pageSize || 10), total.value)
);
const pageRows = computed(() => sortedRows.value.slice(startIndex.value, endIndex.value));

const showingFrom = computed(() => (total.value === 0 ? 0 : startIndex.value + 1));
const showingTo = computed(() => (total.value === 0 ? 0 : endIndex.value));

function setPage(p) {
  emit("update:page", Math.min(Math.max(1, p), lastPage.value));
}
function setPageSize(ps) {
  emit("update:pageSize", Number(ps));
  emit("update:page", 1);
}
</script>

<template>
  <div class="w-full">
    <div v-if="showToolbar" class="mb-3 flex items-center justify-between 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>
      <div class="flex items-center gap-2">
        <label class="text-sm text-gray-600">Na stran</label>
        <select
          class="rounded border-gray-300 text-sm"
          :value="pageSize"
          @change="setPageSize($event.target.value)"
        >
          <option v-for="opt in pageSizeOptions" :key="opt" :value="opt">
            {{ opt }}
          </option>
        </select>
      </div>
    </div>

    <div>
      <Table class="border-t">
        <TableHeader>
          <TableRow class="border-b">
            <TableHead v-for="col in columns" :key="col.key" :class="col.class">
              <Button
                v-if="col.sortable"
                variant="ghost"
                class="text-left gap-1 p-1"
                @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'"
                  ><ArrowDownNarrowWide
                /></span>
                <span v-else-if="sort?.key === col.key && sort.direction === 'desc'"
                  ><ArrowUpWideNarrowIcon
                /></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 && pageRows.length">
            <TableRow
              v-for="(row, idx) in pageRows"
              :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>
                  {{ col.formatter ? col.formatter(row) : 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">
                  <EmptyState :title="emptyText" size="sm" />
                </slot>
              </TableCell>
            </TableRow>
          </template>
        </TableBody>
      </Table>
    </div>
    <div class="px-2 py-4 border-t">
      <DataTablePaginationClient
        v-if="showPagination"
        :current-page="currentPage"
        :last-page="lastPage"
        :total="total"
        :showing-from="showingFrom"
        :showing-to="showingTo"
        :show-page-stats="showPageStats"
        :show-goto="showGoto"
        :max-page-links="maxPageLinks"
        @update:page="setPage"
      />
    </div>
  </div>
</template>
