<script setup>

import { onMounted, ref, watchEffect } from  'vue';
import ProgressBar from './ProgressBar.vue';
import Icon from './Icon.vue';

const emits = defineEmits(['row-click']);

const props = defineProps({
  model: Array,
  busy: false,
  placeholder: 'empty',
  columns: Object,
  hover: {
    type: Boolean,
    default: true
  },
  defaultSortBy: String,
  defaultSortOrder: {
    type: String,
    default: 'asc',
    validator(value, props) {
      return [ 'asc', 'desc' ].includes(value);
    }
  },
  fixedLayout: {
    type: Boolean,
    default: false,
  }
});

const SORT_ORDER = {
  ASC: 'asc',
  DESC: 'desc',
};

const sortOrder = ref(SORT_ORDER.ASC);
const sortBy = ref(null);
const sortedItems =  ref([]);

watchEffect(() => {
  sort(props.model);
});

const finalBusy = ref(false);
let busyTimeout;

watchEffect(() => {
  if (props.busy) {
    busyTimeout = setTimeout(() => { finalBusy.value = true; }, 1000);
  } else {
    clearTimeout(busyTimeout);
    finalBusy.value = false;
  }
});

function sort() {
  sortedItems.value = props.model.sort((a, b) => {
    let sort = 0;

    if (!props.columns[sortBy.value]) return 0;
    if (!props.columns[sortBy.value].sort) return 0;

    if (typeof props.columns[sortBy.value].sort === 'function') {
      sort = props.columns[sortBy.value].sort(a[sortBy.value], b[sortBy.value], a, b);
    } else {
      if (a[sortBy.value] < b[sortBy.value]) sort = -1;
      else sort = 1;
    }

    return sort *= (sortOrder.value === SORT_ORDER.DESC ? -1 : 1);
  });
}

function toggleSort(key) {
  if (!props.columns[key].sort) return;

  if (sortBy.value === key) sortOrder.value = sortOrder.value === SORT_ORDER.ASC ? SORT_ORDER.DESC : SORT_ORDER.ASC;
  else sortBy.value = key;

  sort();
}

function onRowClick(item) {
  emits('row-click', item);
}

onMounted(() => {
  sortBy.value = props.defaultSortBy;
  sortOrder.value = props.defaultSortOrder;
  sort(props.model);
});

</script>

<template>
  <div class="pankow-table-scroll-wrapper">
    <div class="pankow-table-wrapper">
      <table class="pankow-table" :class="{ 'pankow-table-layout-fixed': fixedLayout }">
        <thead class="pankow-table-header" v-if="sortedItems.length !== 0">
          <tr>
            <th v-for="column in Object.keys(columns)"
              class="pankow-table-header-column"
              :class="{ 'pankow-table-header-column-sortable': columns[column].sort, 'pankow-table-cell-hide-mobile': columns[column].hideMobile }"
              :style="{ 'text-align': columns[column].align || null, width: typeof columns[column].width === 'string' ? columns[column].width : 'auto' }"
              @click="toggleSort(column)"
            >
              <Icon v-if="columns[column].icon" :icon="columns[column].icon" />
              {{ columns[column].label }}
              <i v-show="sortBy === column" class="fa-solid" :class="{ 'fa-arrow-up': sortOrder === SORT_ORDER.DESC, 'fa-arrow-down': sortOrder === SORT_ORDER.ASC }"></i>
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-if="busy">
            <td :colspan="Object.keys(columns).length" style="text-align: center; padding: 20px;">
              <ProgressBar mode="indeterminate" :show-track="false" :show-label="false" :slim="true" v-show="finalBusy"/>
            </td>
          </tr>
          <tr v-else-if="!busy && sortedItems.length === 0">
            <td :colspan="Object.keys(columns).length" class="pankow-table-placeholder">{{ placeholder }}</td>
          </tr>
          <tr v-else class="pankow-table-row" :class="{ 'pankow-table-row-with-hover': hover }" v-for="item in sortedItems" @click="onRowClick(item)">
            <td v-for="column in Object.keys(columns)"
              class="pankow-table-cell"
              :style="{ 'text-align': columns[column].align || null, width: typeof columns[column].width === 'string' ? columns[column].width : 'auto' }"
              :class="{ 'pankow-table-cell-hide-mobile': columns[column].hideMobile, 'pankow-table-cell-nowrap': columns[column].nowrap }"
            >
              <slot :name="column" v-if="$slots[column]" :item="item"/>
              <span v-if="!$slots[column]">{{ (column in item) ? (item[column].label || item[column]) : `TableView Error: item has no property '${column}' nor a template with that name` }}</span>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<style>

.pankow-table-scroll-wrapper {
  display: flex;
  flex-direction: column;
  overflow: auto;
}

.pankow-table-wrapper {
  overflow: auto;
  flex-direction: column;
  display: flex;
  height: 100%;
  flex: 1;
  position: relative;
}

.pankow-table {
  width: 100%;
  border-spacing: 0px;
}

.pankow-table-layout-fixed {
  table-layout: fixed;
}

.pankow-table-header {
  top: 0;
  position: sticky;
  z-index: 1; /* avoids see-through table headers if items in the table have opacity set */
}

.pankow-table-header-column {
  text-align: left;
  background-color: var(--pankow-body-background-color);
  font-size: 14px;
  padding: 5px;
  user-select: none;
  border-bottom: 1px solid var(--pankow-color-light-dark);
  white-space: nowrap;
  font-weight: var(--pankow-font-weight-bold);
}

.pankow-table-header-column-sortable {
  cursor: pointer;
}

.pankow-table-header-column-sortable:hover {
  background-color: var(--pankow-color-background-hover);
}

/* height 100% allows cell content to expand */
.pankow-table-row {
  height: 100%;
}

.pankow-table-cell {
  padding: 5px;
  height: 100%;
  overflow: hidden;
}

.pankow-table-row-with-hover:hover {
  background-color: var(--pankow-color-background-hover);
}

.pankow-table-placeholder {
  text-align: center;
  height: 150px;
}

.pankow-table-cell-nowrap {
  white-space: nowrap;
  text-overflow: ellipsis;
}

@media (max-width: 576px) {
  .pankow-table-cell-hide-mobile {
    display: none;
  }
}

</style>
