<script setup lang="ts">
import DataTable from 'primevue/datatable';
import type { DataTableProps, DataTableSlots } from 'primevue/datatable';
import { useId, ref, watch, computed } from 'vue';
import styles from '@visua/typography.module.css';

export interface IVDataTable extends Partial<Omit<DataTableProps, 'pt' | 'dt' | 'ptOptions' | 'unstyled'>>{
  id?: string
  title?: string
}

const props = withDefaults(defineProps<IVDataTable>(), {
  id: () => useId(),
  title: '',
  selection: undefined,
  paginator: false,
  rowsPerPageOptions: undefined,
  rows: 0,
  value: undefined,
  dataKey: undefined,
  showGridlines: false,
  stripedRows: false,
  first: 0,
  totalRecords: 0,
  pageLinkSize: 5,
  paginatorPosition: 'bottom',
  paginatorTemplate: undefined,
  alwaysShowPaginator:true,
  currentPageReportTemplate: '({currentPage} de {totalPages})',
  lazy: false,
  loading: false,
  sortField: undefined,
  sortOrder: undefined,
  nullSortOrder: 1,
  defaultSortOrder: 1,
  sortMode: 'single',
  removableSort: false,
  filters: undefined,
  filterDisplay: undefined,
  globalFilterFields: undefined,
  filterLocale: undefined,
  selectionMode: undefined,
  compareSelectionBy: 'deepEquals',
  metaKeySelection: false,
  contextMenu: false,
  contextMenuSelection: undefined,
  selectAll: undefined,
  rowHover: false,
  csvSeparator: ',',
  exportFilename: 'download',
  exportFunction: undefined,
  resizableColumns: false,
  columnResizeMode: 'fit',
  reorderableColumns: false,
  expandedRows: undefined,
  expandedRowIcon: undefined,
  collapsedRowIcon: undefined,
  rowGroupMode: undefined,
  groupRowsBy: undefined,
  expandableRowGroups: false,
  expandedRowGroups: undefined,
  stateStorage: 'session',
  stateKey: undefined,
  editMode: undefined,
  editingRows: undefined,
  rowClass: undefined,
  rowStyle: undefined,
  scrollable: false,
  scrollHeight: undefined,
  virtualScrollerOptions: undefined,
  frozenValue: undefined,
  breakpoint: '960px',
  showHeaders: true,
  highlightOnSelect: false,
  size: undefined,
  tableClass: undefined,
  tableProps: undefined,
  tableStyle: undefined,
  filterButtonProps: undefined,
  editButtonProps: undefined,
  multiSortMeta: undefined,
})

type VDataTableSlots = DataTableSlots & {
  default?: (props: Record<string, unknown>) => unknown
};

const slots = defineSlots<VDataTableSlots>();


const dataTableSlotKeys = [
  'header',
  'footer',
  'empty',
  'groupheader',
  'groupfooter',
  'loading',
  'expansion',
  'loadingicon',
  'rowreorderindicatorupicon',
  'rowreorderindicatordownicon',
  'rowgrouptogglericon',
  'paginatorcontainer',
  'paginatorstart',
  'paginatorend',
  'paginatorfirstpagelinkicon',
  'paginatorprevpagelinkicon',
  'paginatornextpagelinkicon',
  'paginatorlastpagelinkicon',
  'paginatorrowsperpagedropdownicon',
  'paginatorjumptopagedropdownicon'
] as const;

const availableSlots = computed(() =>
  dataTableSlotKeys.filter((key) => !!slots[key]).map((key) => [key, slots[key]])
);

const dataTableRef = ref();

defineExpose({
  exportCSV: () => dataTableRef.value.exportCSV()
});

const emit = defineEmits([
  'update:selection',
  'update:rows',
  'update:sortField',
  'update:sortOrder',
  'update:multiSortMeta',
  'update:contextMenuSelection',
  'update:expandedRows',
  'update:expandedRowGroups',
  'update:filters',
  'update:editingRows',
  'update:first',
  'page',
  'sort',
  'row-select',
  'row-unselect',
  'filter',
  'value-change',
  'row-click',
  'row-dbclick',
  'row-contextmenu',
  'row-select-all',
  'row-unselect-all',
  'select-all-change',
  'column-resize-end',
  'column-reorder',
  'row-reorder',
  'row-expand',
  'row-collapse',
  'rowgroup-expand',
  'rowgroup-collapse',
  'cell-edit-init',
  'cell-edit-complete',
  'cell-edit-cancel',
  'row-edit-init',
  'row-edit-save',
  'row-edit-cancel',
  'state-restore',
  'state-save',
]);

const localSelection = ref(props.selection);
watch(() => props.selection, (newVal) => {
  if(localSelection.value !== newVal) {
    localSelection.value = newVal;
  }
});
watch(localSelection, (newVal) => {
  if(props.selection !== newVal){
    emit('update:selection', newVal);
  }
});

const localRows = ref(props.rows);
watch(() => props.rows, (newVal) => {
  if(localRows.value !== newVal){
    localRows.value = newVal;
  }
})
watch(localRows, (newVal) => {
  if(props.rows !== newVal){
    emit('update:rows', newVal);
  }
});

const localFirst = ref(props.first);
watch(() => props.first, (newVal) => {
  if(localFirst.value !== newVal){
    localFirst.value = newVal;
  }
})
watch(localFirst, (newVal) => {
  if(props.first !== newVal){
    emit('update:first', newVal);
  }
});

const localSortField = ref(props.sortField);
watch(() => props.sortField, (newVal) => {
    if(localSortField.value !== newVal){
      localSortField.value = newVal;
    }
})
watch(localSortField, (newVal) => {
    if(props.sortField !== newVal){
        emit('update:sortField', newVal);
    }
});

const localSortOrder = ref(props.sortOrder);
watch(() => props.sortOrder, (newVal) => {
    if(localSortOrder.value !== newVal){
        localSortOrder.value = newVal;
    }
})
watch(localSortOrder, (newVal) => {
    if(props.sortOrder !== newVal){
        emit('update:sortOrder', newVal);
    }
});

const localMultiSortMeta = ref(props.multiSortMeta);
watch(() => props.multiSortMeta, (newVal) => {
    if(localMultiSortMeta.value !== newVal){
        localMultiSortMeta.value = newVal;
    }
})
watch(localMultiSortMeta, (newVal) => {
    if(props.multiSortMeta !== newVal){
        emit('update:multiSortMeta', newVal);
    }
});

const localContextMenuSelection = ref(props.contextMenuSelection);
watch(() => props.contextMenuSelection, (newVal) => {
    if(localContextMenuSelection.value !== newVal){
        localContextMenuSelection.value = newVal;
    }
})
watch(localContextMenuSelection, (newVal) => {
    if(props.contextMenuSelection){
        emit('update:contextMenuSelection', newVal);
    }
});

const localExpandedRows = ref(props.expandedRows);
watch(() => props.expandedRows, (newVal) => {
    if(localExpandedRows.value !== newVal){
        localExpandedRows.value = newVal;
    }
})
watch(localExpandedRows, (newVal) => {
    if(props.expandedRows !== newVal){
        emit('update:expandedRows', newVal);
    }
});

const localExpandedRowGroups = ref(props.expandedRowGroups);
watch(() => props.expandedRowGroups, (newVal) => {
    if(localExpandedRowGroups.value !== newVal){
        localExpandedRowGroups.value = newVal;
    }
})
watch(localExpandedRowGroups, (newVal) => {
    if(props.expandedRowGroups !== newVal){
        emit('update:expandedRowGroups', newVal);
    }
});

const localFilters = ref(props.filters);
watch(() => props.filters, (newVal) => {
    if(localFilters.value !== newVal){
        localFilters.value = newVal;
    }
})
watch(localFilters, (newVal) => {
    if(props.filters !== newVal){
        emit('update:filters', newVal);
    }
});

const localEditingRows = ref(props.editingRows);
watch(() => props.editingRows, (newVal) => {
    if(localEditingRows.value = newVal){
        localEditingRows.value = newVal;
    }
})
watch(localEditingRows, (newVal) => {
    if(props.editingRows !== newVal){
        emit('update:editingRows', newVal);
    }
});

</script>

<template>
  <DataTable
    :id="`datatable-${props.id}`"
    role="table"
    ref="dataTableRef"
    :value="props.value"
    :paginator="props.paginator"
    :rowsPerPageOptions="props.rowsPerPageOptions"
    :data-key="props.dataKey"
    :show-gridlines="props.showGridlines"
    :striped-rows="props.stripedRows"
    :total-records="props.totalRecords"
    :page-link-size="props.pageLinkSize"
    :paginator-position="props.paginatorPosition"
    :paginator-template="props.paginatorTemplate"
    :always-show-paginator="props.alwaysShowPaginator"
    :current-page-report-template="props.currentPageReportTemplate"
    :lazy="props.lazy"
    :loading="props.loading"
    :nullSortOrder="props.nullSortOrder"
    :defaultSortOrder="props.defaultSortOrder"
    :sortMode="props.sortMode"
    :removableSort="props.removableSort"
    :filterDisplay="props.filterDisplay"
    :globalFilterFields="props.globalFilterFields"
    :filterLocale="props.filterLocale"
    :selectionMode="props.selectionMode"
    :compareSelectionBy="props.compareSelectionBy"
    :metaKeySelection="props.metaKeySelection"
    :contextMenu="props.contextMenu"
    :selectAll="props.selectAll"
    :rowHover="props.rowHover"
    :csvSeparator="props.csvSeparator"
    :exportFilename="props.exportFilename"
    :exportFunction="props.exportFunction"
    :resizableColumns="props.resizableColumns"
    :columnResizeMode="props.columnResizeMode"
    :reorderableColumns="props.reorderableColumns"
    :expandedRowIcon="props.expandedRowIcon"
    :collapsedRowIcon="props.collapsedRowIcon"
    :rowGroupMode="props.rowGroupMode"
    :groupRowsBy="props.groupRowsBy"
    :expandableRowGroups="props.expandableRowGroups"
    :stateStorage="props.stateStorage"
    :stateKey="props.stateKey"
    :editMode="props.editMode"
    :rowClass="props.rowClass"
    :rowStyle="props.rowStyle"
    :scrollable="props.scrollable"
    :scrollHeight="props.scrollHeight"
    :virtualScrollerOptions="props.virtualScrollerOptions"
    :frozenValue="props.frozenValue"
    :breakpoint="props.breakpoint"
    :showHeaders="props.showHeaders"
    :highlightOnSelect="props.highlightOnSelect"
    :size="props.size"
    :tableClass="props.tableClass"
    :tableProps="props.tableProps"
    :tableStyle="props.tableStyle"
    :filterButtonProps="props.filterButtonProps"
    :editButtonProps="props.editButtonProps"
    style="width: 100%; height: fit-content;"
    v-model:selection="localSelection"
    v-model:rows="localRows"
    v-model:first="localFirst"
    v-model:sortField="localSortField"
    v-model:sortOrder="localSortOrder"
    v-model:filters="localFilters"
    v-model:contextMenuSelection="localContextMenuSelection"
    v-model:expandedRows="localExpandedRows"
    v-model:expandedRowGroups="localExpandedRowGroups"
    v-model:editingRows="localEditingRows"
    v-model:multi-sort-meta="localMultiSortMeta"
    @update:selection="emit('update:selection', $event)"
    @update:context-menu-selection="emit('update:contextMenuSelection', $event)"
    @update:editing-rows="emit('update:editingRows', $event)"
    @update:expanded-row-groups="emit('update:expandedRowGroups', $event)"
    @update:filters="emit('update:filters', $event)"
    @update:first="emit('update:first', $event)"
    @update:multi-sort-meta="emit('update:multiSortMeta', $event)"
    @update:rows="emit('update:rows', $event)"
    @update:sort-field="emit('update:sortField', $event)"
    @update:sort-order="emit('update:sortOrder', $event)"
    @page="emit('page', $event)"
    @sort="emit('sort', $event)"
    @rowSelect="emit('row-select', $event)"
    @rowUnselect="emit('row-unselect', $event)"
    @filter="emit('filter', $event)"
    @valueChange="emit('value-change', $event)"
    @rowClick="emit('row-click', $event)"
    @rowCollapse="emit('row-collapse', $event)"
    @rowContextmenu="emit('row-contextmenu', $event)"
    @rowDblclick="emit('row-dbclick', $event)"
    @rowEditCancel="emit('row-edit-cancel', $event)"
    @rowEditInit="emit('row-edit-init', $event)"
    @rowEditSave="emit('row-edit-save', $event)"
    @rowExpand="emit('row-expand', $event)"
    @rowReorder="emit('row-reorder', $event)"
    @rowSelectAll="emit('row-select-all', $event)"
    @rowUnselectAll="emit('row-unselect-all', $event)"
    @rowgroupCollapse="emit('rowgroup-collapse', $event)"
    @rowgroupExpand="emit('rowgroup-expand', $event)"
    @columnReorder="emit('column-reorder', $event)"
    @columnResizeEnd="emit('column-resize-end', $event)"
    @cellEditCancel="emit('cell-edit-cancel', $event)"
    @cellEditComplete="emit('cell-edit-complete', $event)"
    @cellEditInit="emit('cell-edit-init', $event)"
    @stateRestore="emit('state-restore', $event)"
    @stateSave="emit('state-save', $event)"
    @selectAllChange="emit('select-all-change', $event)"
    class="p-datatable"
  >
    <template
      v-for="([name]) in availableSlots"
      :key="name"
      v-slot:[name]="slotProps"
    >
      <slot :name="name" v-bind="slotProps" />
    </template>
    <slot></slot>
    <template #empty>
      <div class="datatable-empty" :class="[styles['text-body-SM-detail-text-Regular']]">
        <i class="ri-database-line database-icon"></i>
        <p> Aucune donnée trouvée. </p>
      </div>
    </template>
  </DataTable>
</template>

<style lang="css" scoped>
.p-datatable{
  box-sizing: border-box;
}

.datatable-empty{
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 1rem;
  gap: 1.5rem;
}

.database-icon{
  font-size: 5rem;
  color: var(--border-contrast-grey);
}
</style>
