<template>

  <div class="itf-table__wrapper"
       :style="{'--itf-table-template': columnsGridStyle}"
       :class="{
          'itf-table__sticky-header': stickyHeader,
          'itf-table__sticky-column': stickyColumn,
          'itf-table__sticky-last-column': stickyLastColumn,
          'itf-table__small': small,
          'scrolled-x': scrolledX,
          'scrolled-right': scrolledEnd,
          'scrolled-y': scrolledY
       }">
    <div
      class="itf-table"
      :class="{
        'itf-table--striped': striped,
        'itf-table--hoverable': hoverable,
      }">
      <div class="itf-table__headers" ref="stickyHeader">
        <div class="scroller" ref="scrollContainer">
          <div class="itf-table__header-row">
            <div
              class="itf-table__header"
              v-for="(column, n) in columns"
              :key="n"
              :class="{
                'itf-table__header--sortable': column.sortable,
                'itf-table__header--sorted': sortedColumns[column.name],
                [`itf-table__header--sorted-${sortedColumns[column.name]}`]: sortedColumns[column.name],
                 'align-left': column.alignLeft
              }">
              <span @click="sortBy(column, n)">
                {{column.text}}
              </span>
            </div>
          </div>
        </div>
      </div>
      <div v-show="rows && rows.length" class="itf-table__rows" ref="scrollContainer2">
        <div class="itf-table__row"
             :class="{'itf-table__summary-row': row.summary}"
             v-for="(row, r) in rows"
             :key="r"
             @click="!row.summary && $emit('row-click', { row, index: r })">
          <div
            class="itf-table__cell"
            :class="{'itf-table__cell--sorted': sortedColumns[column.name], 'align-left': column.alignLeft}"
            v-for="(column, k) in columns" :key="`${r}-${k}`">
            <span class="w-100">
              <slot v-if="$scopedSlots[`column.${column.name}${row.summary ? '.summary' : ''}`]" :name="`column.${column.name}${row.summary ? '.summary' : ''}`" :item="row" :column="column">
                {{row[column.name]}}
              </slot>
              <slot v-else :name="`column`" :item="row" :column="column"></slot>
            </span>
          </div>
        </div>
      </div>
      <div v-if="!rows || !rows.length" class="itf-table__nodata">
        <slot name="nodata" :loading="loading">
          <div class="text-center pa-5">
            <span v-if="loading">Loading...</span>
            <span v-else>No data</span>
          </div>
        </slot>
      </div>
    </div>
  </div>

</template>
<script>
import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
import itfButton from '../button/Button.vue';
import itfIcon from '../icon/Icon.vue';

export default @Component({
  name: 'itfTable',
  components: {
    itfButton,
    itfIcon,
  }
})
class itfTable extends Vue {
  @PropSync('sorting', { type: Object, default: () => ({}) }) sortedColumns;
  @Prop({ required: true, type: Array }) columns;
  @Prop({ required: true, type: Array }) rows;
  @Prop({ default: false, type: Boolean }) stickyHeader;
  @Prop({ default: false, type: Boolean }) stickyColumn;
  @Prop({ default: false, type: Boolean }) stickyLastColumn;
  @Prop({ default: false, type: Boolean }) loading;
  @Prop({ default: false, type: Boolean }) striped;
  @Prop({ default: false, type: Boolean }) hoverable;
  @Prop({ default: false, type: Boolean }) small;

  sortDirection = 'asc';
  scrolledX = false;
  scrolledEnd = false;
  scrolledY = false;
  stickyObserver = null;

  scrollFunc = null;

  mounted() {
    if (this.$refs.scrollContainer && this.$refs.scrollContainer2) {
      this.scrollFunc = initSyncScroll(this.$refs.scrollContainer, this.$refs.scrollContainer2, (isEnd) => {
        this.scrolledX = true;
        this.scrolledEnd = isEnd;
      }, () => {
        this.scrolledX = false;
      });
    } else {
      setTimeout(() => {
        this.scrollFunc = initSyncScroll(this.$refs.scrollContainer, this.$refs.scrollContainer2, (isEnd) => {
          this.scrolledX = true;
          this.scrolledEnd = isEnd;
        }, () => {
          this.scrolledX = false;
        });
      }, 1000);
    }

    if (this.$refs.stickyHeader) {
      this.stickyObserver = new IntersectionObserver(([e]) => {
        return this.scrolledY = e.intersectionRatio < 1;
      }, {
        rootMargin: `-${this.$refs.stickyHeader.offsetHeight + 5}px 0px 0px 0px`,
        threshold: [1]
      });
      this.stickyObserver.observe(this.$refs.stickyHeader);
    }
    function initSyncScroll(el1, el2, stuck, unstuck) {
      function isScrolledEnd(el) {
        return el.scrollWidth === el.getBoundingClientRect().width // якщо контейнер менший ширини екрану
          || el.scrollLeft === el.scrollWidth - el.getBoundingClientRect().width; // якщо контейнер більший ширини екрану
      }

      function func1() {
        el2.scrollLeft = el1.scrollLeft;
        if (el1.scrollLeft > 0) {
          stuck(isScrolledEnd(el1));
        } else {
          unstuck();
        }
      }

      function func2() {
        el1.scrollLeft = el2.scrollLeft;
        if (el2.scrollLeft > 0) {
          stuck(isScrolledEnd(el2));
        } else {
          unstuck();
        }
      }

      if (isScrolledEnd(el1)) {
        stuck(true);
        unstuck();
      }

      el1.addEventListener('scroll', func1);
      el2.addEventListener('scroll', func2);

      return [func1, func2];
    }
  }

  beforeDestroy() {
    if (this.scrollFunc) {
      const [func1, func2] = this.scrollFunc;
      this.$refs.scrollContainer.removeEventListener('scroll', func1);
      this.$refs.scrollContainer2.removeEventListener('scroll', func2);
    }
  }

  get columnsGridStyle() {
    return this.columns.map((column) => {
      if (column.min) {
        return `minmax(${column.min}px, ${column.max ? `${column.max}px` : 'auto'})`;
      }
      return `${column.fraction || 1}fr`;
    }).join(' ');
  }

  sortBy(column, index) {
    if (!column.sortable) {
      return;
    }
    const { name } = this.columns[index];
    const direction = this.sortedColumns[name] === 'asc' ? 'desc' : 'asc';
    this.sortedColumns = { [name]: direction };
  }
}
</script>
