<template>
  <div class="data-table">
    <div v-if="searchable || $slots.toolbar" class="toolbar-row mb-2">
      <v-text-field
        v-if="searchable"
        v-model="query"
        :placeholder="searchPlaceholder"
        density="compact"
        hide-details
        clearable
        prepend-inner-icon="mdi-filter-variant"
        style="max-width: 280px"
      />
      <slot name="toolbar" />
    </div>

    <div class="table-scroll" :style="stickyHeader ? { maxHeight } : {}">
      <table class="asset-table" :class="{ 'sticky-head': stickyHeader }">
        <thead>
          <tr>
            <th v-if="hasLead" class="lead-col"><slot name="lead-header" /></th>
            <th
              v-for="col in columns"
              :key="col.key"
              :class="[alignClass(col), { sortable: col.sortable !== false }]"
              @click="toggleSort(col)"
            >
              <span class="th-label">
                {{ col.label }}
                <v-icon v-if="sortKey === col.key" :icon="sortDir === 1 ? 'mdi-menu-up' : 'mdi-menu-down'" size="16" />
              </span>
            </th>
            <th v-if="hasActions" class="actions-col" />
          </tr>
        </thead>
        <tbody>
          <tr v-for="(row, index) in pagedRows" :key="keyFor(row, index)">
            <td v-if="hasLead" class="lead-col"><slot name="lead" :row="row" /></td>
            <td v-for="col in columns" :key="col.key" :class="alignClass(col)">
              <slot :name="`cell-${col.key}`" :row="row" :value="row[col.key]">
                {{ formatCell(row[col.key], col.format) }}
              </slot>
            </td>
            <td v-if="hasActions" class="text-right actions-col"><slot name="actions" :row="row" /></td>
          </tr>
          <tr v-if="!pagedRows.length">
            <td :colspan="colspan" class="quiet">{{ emptyText }}</td>
          </tr>
        </tbody>
        <tfoot v-if="totals">
          <tr>
            <td v-if="hasLead" />
            <td v-for="(col, i) in columns" :key="col.key" :class="['font-weight-bold', alignClass(col)]">
              {{ i === 0 ? 'Totals' : (col.key in totals ? formatCell(totals[col.key], col.format || 'currency') : '') }}
            </td>
            <td v-if="hasActions" />
          </tr>
        </tfoot>
      </table>
    </div>

    <div class="data-table-footer">
      <span class="quiet text-caption">{{ rangeLabel }}</span>
      <v-spacer />
      <span class="quiet text-caption mr-1">Rows per page</span>
      <v-select
        v-model="perPage"
        :items="pageSizeItems"
        item-title="title"
        item-value="value"
        density="compact"
        variant="plain"
        hide-details
        style="max-width: 78px"
      />
      <v-pagination
        v-if="pageCount > 1"
        v-model="page"
        :length="pageCount"
        :total-visible="5"
        density="comfortable"
        class="ml-2"
      />
    </div>
  </div>
</template>

<script>
import { currency, shortDate } from '../utils/format';

export default {
  props: {
    columns: { type: Array, required: true },
    rows: { type: Array, required: true },
    rowKey: { type: [String, Function], default: 'id' },
    totals: { type: Object, default: null },
    searchable: { type: Boolean, default: false },
    searchPlaceholder: { type: String, default: 'Filter rows' },
    pageSize: { type: Number, default: 25 },
    pageSizeOptions: { type: Array, default: () => [10, 25, 50, 100] },
    stickyHeader: { type: Boolean, default: true },
    maxHeight: { type: String, default: '62vh' },
    hasActions: { type: Boolean, default: false },
    hasLead: { type: Boolean, default: false },
    emptyText: { type: String, default: 'No data.' }
  },
  data() {
    return {
      sortKey: null,
      sortDir: 1,
      page: 1,
      perPage: this.pageSize,
      query: ''
    };
  },
  computed: {
    pageSizeItems() {
      return [...this.pageSizeOptions.map((n) => ({ title: String(n), value: n })), { title: 'All', value: -1 }];
    },
    colspan() {
      return this.columns.length + (this.hasLead ? 1 : 0) + (this.hasActions ? 1 : 0);
    },
    filteredRows() {
      if (!this.searchable || !this.query) return this.rows;
      const needle = String(this.query).toLowerCase();
      return this.rows.filter((row) =>
        this.columns.some((col) => String(row[col.key] ?? '').toLowerCase().includes(needle))
      );
    },
    sortedRows() {
      if (!this.sortKey) return this.filteredRows;
      const col = this.columns.find((c) => c.key === this.sortKey);
      const numeric = col && (col.format === 'currency' || col.format === 'number');
      const dated = col && col.format === 'date';
      const dir = this.sortDir;
      return [...this.filteredRows].sort((a, b) => {
        let av = a[this.sortKey];
        let bv = b[this.sortKey];
        if (numeric) return (Number(av || 0) - Number(bv || 0)) * dir;
        if (dated) return ((new Date(av || 0)) - (new Date(bv || 0))) * dir;
        av = String(av ?? '');
        bv = String(bv ?? '');
        return av.localeCompare(bv, undefined, { numeric: true }) * dir;
      });
    },
    pageCount() {
      if (this.perPage === -1) return 1;
      return Math.max(1, Math.ceil(this.sortedRows.length / this.perPage));
    },
    pagedRows() {
      if (this.perPage === -1) return this.sortedRows;
      const start = (this.page - 1) * this.perPage;
      return this.sortedRows.slice(start, start + this.perPage);
    },
    rangeLabel() {
      const total = this.sortedRows.length;
      if (!total) return '0 of 0';
      if (this.perPage === -1) return `1–${total} of ${total}`;
      const start = (this.page - 1) * this.perPage + 1;
      const end = Math.min(start + this.perPage - 1, total);
      return `${start}–${end} of ${total}`;
    }
  },
  watch: {
    rows() {
      if (this.page > this.pageCount) this.page = this.pageCount;
    },
    perPage() {
      this.page = 1;
    },
    query() {
      this.page = 1;
    }
  },
  methods: {
    toggleSort(col) {
      if (col.sortable === false) return;
      if (this.sortKey === col.key) {
        if (this.sortDir === 1) this.sortDir = -1;
        else this.sortKey = null;
      } else {
        this.sortKey = col.key;
        this.sortDir = 1;
      }
    },
    alignClass(col) {
      return col.align === 'end' || col.format === 'currency' || col.format === 'number' ? 'text-right' : '';
    },
    keyFor(row, index) {
      if (typeof this.rowKey === 'function') {
        const key = this.rowKey(row);
        return key == null ? index : key;
      }
      return row[this.rowKey] ?? index;
    },
    formatCell(value, format) {
      if (value === null || value === undefined || value === '') return '';
      if (format === 'currency') return currency(value);
      if (format === 'number') return Number(value).toLocaleString();
      if (format === 'date') return shortDate(value);
      return value;
    }
  }
};
</script>
