<template>

  <div class="itf-table2__header" :class="{'no-header': !visibleHeader}">
    <div ref="container" class="table-row-template">
      <div accept-group="items" class="table-view-body-space" v-dropzone="{ payload: 0 }"></div>
      <div class="shadow-area"></div>
      <div class="table-view-header-value reserved sticky" data-test="table-header-checkbox">
        <itf-checkbox v-if="indicatorType === 'checkbox' && visibleHeader && !noSelectAll" ungrouped value="all" v-model="selectAll" ref="selectAll" />
      </div>

      <template v-for="(column, n) in visibleAttributes">
        <div
          v-if="column.visible !== false"
          :key="n"
          data-test="table-header-column"
          :data-column="n"
          :data-id="column.Id"
          :class="{'sticky': column.pinned && !getIsMobileView(), 'active': sortColumnParams[column.property], 'last-sticky-column': n === lastPinnedIndex && !getIsMobileView(), [`justify-content-${column.align || 'start'}`]: true}"
          class="table-view-header-value"
          :style="`width: ${column.width}px; max-width: ${column.width}px; left: ${column.left}px;`">
          <!-- Не треба видаляти колонки, бо вони потрібні для збереження ширини -->
          <div v-if="visibleHeader" accept-group="tablecolumns"
               class="table-view-header-space"
               @enter="columnHighlight(n, 'enter')"
               @leave="columnHighlight(n, 'leave')"
               v-dropzone="{ payload: { index: n, attribute: column } }">
            <div class="table-view-header-dropzone"></div>
          </div>
          <div v-if="visibleHeader" group="tablecolumns"
               class="table-header"
               @drop="reorderColumns"
               v-draggable="{ handle: true, payload: { index: n, item: column }, mirror: {yAxis:false} }">
            <div class="d-flex align-items-center gap-1">
              <itf-dropdown text append-to-body shadow ref="dropdown" class="w-100" :disabled="noColumnMenu">
                <template #button>
                  <div class="d-flex align-items-start justify-content-between">
                    <div class="itf-table2__header-title d-flex w-100 align-items-center" :title="getTitle(column.title)">
                      <itf-icon class="itf-table2__header-icon" new v-if="column.icon" :name="column.icon"></itf-icon>
                      <div class="flex-grow-1 w-100 itf-table2__title-container d-flex align-items-center" :class="{'justify-content-end': column.align === 'end'}">
                        <div class="itf-table2__title text-truncate">{{getTitle(column.title)}}</div>
                        <div v-if="column.prefix" class="itf-table2__subtitle text-truncate" v-text="column.prefix" />
                      </div>
                    </div>
                    <itf-icon v-if="sortColumnParams[column.property]" :name="sortColumnParams[column.property] === 'asc' ? 'sort-asc' : 'sort-desc'" new :size="20" class="ms-1" />
                  </div>
                </template>
                <div class="dropdown-header">
                  {{$t('components.table.actions')}}
                </div>

                <div v-if="column.groupable">
                  <a class="dropdown-item d-flex align-items-center"  href="javascript:;">
                    <itf-icon name="episodes" :size="16" class="me-1" />
                    {{$t('components.table.groupBy')}}
                  </a>
                </div>
                <div>
                  <a class="dropdown-item d-flex align-items-center gap-1"  href="javascript:;" @click="togglePinned(n)">
                    <itf-icon v-if="column.pinned" name="pin" new />
                    <itf-icon v-else name="pin" new />

                    <span v-if="column.pinned">{{$t('components.table.unfreezeColumn')}}</span>
                    <span v-else>{{$t('components.table.freezeColumn')}}</span>
                  </a>
                </div>
                <div v-if="showAddColumn">
                  <a class="dropdown-item d-flex align-items-center gap-1"  href="javascript:;" @click="hideColumn(n)">
                    <itf-icon name="hide" new />

                    {{$t('components.table.hideColumn')}}
                  </a>
                </div>
                <div v-if="column.filtrable">
                  <a class="dropdown-item d-flex align-items-center gap-1"  href="javascript:;" @click="$emit('filter', column)">
                    <itf-icon name="filter" new />

                    {{$t('components.table.filter')}}
                  </a>
                </div>
                <div v-if="canMoveColumn(1, column)">
                  <a class="dropdown-item d-flex align-items-center gap-1"  href="javascript:;" @click="moveColumn(1, column)">
                    <itf-icon name="move-right" new />

                    {{$t('components.table.moveRight')}}
                  </a>
                </div>

                <div v-if="canMoveColumn(-1, column)">
                  <a class="dropdown-item d-flex align-items-center gap-1"  href="javascript:;" @click="moveColumn(-1, column)">
                    <itf-icon name="move-left" new />

                    {{$t('components.table.moveLeft')}}
                  </a>
                </div>

                <template v-if="column.sortable">
                  <div class="dropdown-header">
                    {{$t('components.table.sorting')}}
                  </div>
                  <div>
                    <a class="dropdown-item d-flex align-items-center gap-1"  href="javascript:;" @click="sortBy(column, 'asc')">
                      <itf-icon name="sort-asc" new />
                      {{$t('components.table.sortAscending')}}
                    </a>
                  </div>
                  <div>
                    <a class="dropdown-item d-flex align-items-center gap-1"  href="javascript:;" @click="sortBy(column, 'desc')">
                      <itf-icon name="sort-desc" new />
                      {{$t('components.table.sortDescending')}}
                    </a>
                  </div>
                </template>
              </itf-dropdown>
              <slot :name="`header.${column.property}.after`" v-bind="{ column }"></slot>
            </div>
            <div v-if="columnSorting" v-drag-handle class="itf-table2__drag-column">
              <svg width="35" height="23" viewBox="0 0 35 23" fill="none" xmlns="http://www.w3.org/2000/svg">
                <g filter="url(#filter0_d_1081_25763)">
                  <rect x="4" y="2" width="27" height="15" rx="4" fill="#1A4A97"/>
                  <circle cx="23.5" cy="9.5" r="1.5" fill="white"/>
                  <circle cx="17.5" cy="9.5" r="1.5" fill="white"/>
                  <circle cx="11.5" cy="9.5" r="1.5" fill="white"/>
                </g>
                <defs>
                  <filter id="filter0_d_1081_25763" x="0" y="0" width="35" height="23" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
                    <feFlood flood-opacity="0" result="BackgroundImageFix"/>
                    <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
                    <feOffset dy="2"/>
                    <feGaussianBlur stdDeviation="2"/>
                    <feComposite in2="hardAlpha" operator="out"/>
                    <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
                    <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1081_25763"/>
                    <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1081_25763" result="shape"/>
                  </filter>
                </defs>
              </svg>
            </div>
          </div>
          <div v-if="visibleHeader && n === sortedColumns.length - 1"
               @enter="columnHighlightLast('enter')"
               @leave="columnHighlightLast('leave')"
               accept-group="tablecolumns"
               class="table-view-header-space right"
               v-dropzone="{payload:{ last: true }}">
            <div class="table-view-header-dropzone"></div>
          </div>
          <div v-if="visibleHeader && columnResizing" ref="resizeHandle" class="resize-handle"></div>
        </div>
      </template>
      <div class="table-view-item-value extra flex-grow-1"></div>

      <div class="boundary top"></div>
      <div class="boundary right"></div>
      <div class="boundary bottom"></div>
      <div class="boundary left"></div>
    </div>
  </div>

</template>
<script>
import {Vue, Component, Prop, PropSync, Watch, Inject} from 'vue-property-decorator';
import itfCheckbox from '../checkbox/Checkbox.vue';
import itfButton from '../button/Button.vue';
import itfPopover from '../popover/Popover.vue';
import itfIcon from '../icon/Icon.vue';
import createDraggable from '../sortable/draggable';
import itfDropdown from '../dropdown/Dropdown.vue';
import itfSortable from '../sortable/Sortable.vue';
import settings from "../../ITFSettings";
import { getIsMobileView } from "./mobile";

const { Node, ...draggableDirectives } = createDraggable();

export default @Component({
  name: 'itfTableHeader',
  components: {
    itfSortable,
    itfCheckbox,
    itfDropdown,
    itfButton,
    itfPopover,
    itfIcon
  },
  directives: {
    ...draggableDirectives
  }
})
class itfTableHeader extends Vue {
  @Inject() tableEl;

  @PropSync('columns', { type: Array, default: () => ([]) }) sortedColumns;
  @PropSync('sorting') _sorting;
  @Prop({ type: Array, default: () => ([]) }) rows;
  @Prop({ type: Array, default: () => ([]) }) selectedIds;
  @Prop({ type: Object, default: () => ({}) }) schema;
  @Prop(Boolean) columnSorting;
  @Prop(Boolean) columnResizing;
  @Prop(Boolean) showAddColumn;
  @Prop(Boolean) visibleHeader;
  @Prop(Boolean) noColumnMenu;
  @Prop(Boolean) noSelectAll;
  @Prop(Boolean) editable;
  @Prop() idProperty;
  @Prop() indicatorType;

  @Watch('selectedIds')
  @Watch('rows')
  onSelectedIdChanged() {
    if (this.$refs.selectAll && this.selectedIds.length && this.selectedIds.length < this.rows.length) {
      this.$refs.selectAll.input.indeterminate = true;
    } else if (this.$refs.selectAll && this.$refs.selectAll.input) {
      this.$refs.selectAll.input.indeterminate = false;
    }
  }

  getIsMobileView() {
    return getIsMobileView();
  }

  get sortColumnParams() {
    if (typeof this._sorting === 'string'){
      return this._sorting[0] === '-' ? {[this._sorting.substring(1)]: 'desc'} : {[this._sorting]: 'asc'};
    } else {
      return this._sorting ?? {};
    }
  }

  getTitle(title) {
    if (typeof title === 'string') {
      return title;
    }
    return title[this.locale] || title['en_US'];
  }

  get locale() {
    return settings.defaultLocale;
  }

  get selectAll() {
    return this.selectedIds.length === this.rows.length;
  }

  set selectAll(val) {
    if (val) {
      this.$emit('update:selectedIds', this.rows.filter(r => !r.isDisabled).map(r => r[this.idProperty]));
    } else {
      this.$emit('update:selectedIds', []);
    }
  }

  addColumn(column) {
    const index = this.sortedColumns.findIndex((c) => c === column);
    const newValue = [...this.sortedColumns];
    newValue[index].visible = true;
    this.$emit('update:columns', newValue);
    this.$refs.newDd.hide();
  }

  get invisibleColumns() {
    return this.sortedColumns.filter((column) => column.visible === false);
  }

  get visibleAttributes() {
    return this.sortedColumns;
  }

  get lastPinnedIndex() {
    return this.sortedColumns.findIndex((column) => column.lastPinned);
  }

  canMoveColumn(direction, column) {
    if (!this.columnSorting) {
      return false;
    }
    const index = this.sortedColumns.findIndex((c) => c === column);
    return (index + direction >= 0 && index + direction < this.sortedColumns.length);
  }

  moveColumn(direction, column) {
    const index = this.sortedColumns.findIndex((c) => c === column);
    const newIndex = index + direction;
    if (newIndex < 0 || newIndex >= this.sortedColumns.length) {
      return;
    }
    const newValue = [...this.sortedColumns];
    newValue.splice(index, 1);
    newValue.splice(newIndex, 0, column);
    this.$emit('update:columns', newValue);
  }

  reorderColumns({ detail }) {
    const { index: fromIndex } = detail.draggablePayload;
    const { index: toIndex, last } = detail.dropzonePayload;
    const newValue = [...this.sortedColumns];
    const [removed] = newValue.splice(fromIndex, 1);
    let putIndex = (removed.pinned && toIndex > this.lastPinnedIndex + 1) ? this.lastPinnedIndex : toIndex;
    if (!removed.pinned && toIndex <= this.lastPinnedIndex) {
      putIndex = this.lastPinnedIndex + 1;
    }

    if (last) {
      newValue.push(removed);
    } else {
      newValue.splice((fromIndex < putIndex) ? putIndex - 1 : putIndex, 0, removed);
    }
    this.$emit('sort:columns', newValue);
    if (last) {
      this.columnHighlightLast('leave');
    } else {
      this.columnHighlight(toIndex, 'leave');
    }
  }

  columnHighlight(index, state) {
    Array.from(this.tableEl.$el.querySelectorAll(`[data-column="${index}"]`)).forEach(t=>{
      state === "enter" ? t.classList.add("highlight-drop-column") : t.classList.remove("highlight-drop-column")
    });
  }

  columnHighlightLast(state) {
    Array.from(this.tableEl.$el.querySelectorAll(`[data-column="${this.sortedColumns.length - 1}"]`)).forEach(t=>{
      if (state === "enter") {
        t.classList.add("highlight-drop-column");
        t.classList.add("right");
      } else {
        t.classList.remove("highlight-drop-column");
        t.classList.remove("right");
      }
    });
  }

  initResizing() {
    const resizeHandle = this.$refs.resizeHandle;
    if (!resizeHandle) {
      return;
    }
    resizeHandle.forEach((handle) => {
      if (handle.binded) {
        return;
      }
      handle.binded = true;
      handle.addEventListener('mousedown', (event) => {
        const column = event.target.closest('.table-view-header-value');
        const body = event.target.closest('.table-view-body');
        const columnWidth = column.offsetWidth;
        const startX = event.pageX;
        const index = column.getAttribute('data-column');
        const columns = body.querySelectorAll(`[data-column="${index}"]`);
        let newWidth;
        const mouseMoveHandler = (event) => {
          const delta = event.pageX - startX;
          newWidth = Math.max(columnWidth + delta, 50);
          columns.forEach((column) => {
            const { maxWidth, minWidth } = this.sortedColumns[index];
            if (minWidth && newWidth < minWidth) {
              newWidth = minWidth;
            }
            if (maxWidth && newWidth > maxWidth) {
              newWidth = maxWidth;
            }
            column.style.width = `${newWidth}px`;
            column.style['max-width'] = `${newWidth}px`;
          });
        };
        const mouseUpHandler = () => {
          document.removeEventListener('mousemove', mouseMoveHandler);
          document.removeEventListener('mouseup', mouseUpHandler);
          const { minWidth, maxWidth } = this.sortedColumns[index];
          if (minWidth && newWidth < minWidth) {
            newWidth = minWidth;
          }
          if (maxWidth && newWidth > maxWidth) {
            newWidth = maxWidth;
          }
          this.changeColumn(index, { width: newWidth });
        };
        document.addEventListener('mousemove', mouseMoveHandler);
        document.addEventListener('mouseup', mouseUpHandler);
      });
    });
  }

  beforeDestroy() {
    if (this.columnSorting) {
      Node.removeContainer(this.$refs.container);
    }
  }

  mounted() {
    if (this.columnSorting) {
      Node.addContainer(this.$refs.container);
    }
    if (this.columnResizing) {
      this.onColumnsChanged();
    }
  }

  @Watch('columns')
  onColumnsChanged() {
    this.$nextTick(() => this.initResizing());
  }

  changeColumn(index, params) {
    let newValue = [...this.sortedColumns];
    const newItem = { ...newValue[index] };
    Object.assign(newItem, params);
    newValue[index] = newItem;
    this.$emit('update:columns', newValue);
  }

  hideColumn(index) {
    this.changeColumn(index, { visible: false });
  }

  togglePinned(index) {
    this.changeColumn(index, { pinned: !this.sortedColumns[index].pinned });
  }

  onSortColumns(items) {
    this.$emit('update:columns', items);
  }

  sortBy(column, order) {
    let sort = order === 'desc' ? `-${column.property}` : column.property;
    console.info(sort);
    this.$emit('update:sorting', sort);
  }
}
</script>
