<template>

  <div class="itf-table-group table-small-row" :class="{'no-indicator': indicatorType === 'none'}">
    <!-- Тут показується лінія при драг н дропі -->
    <!--div accept-group="tablegroups" class="preline">
      <div class="line"></div>
    </div-->

    <div data-test="table-group-wrapper" class="table-group-wrapper flex-grow-1 w-100 d-block"
         :style="`--row-count: ${isShowTable ? rows.length : 0}`">
      <div data-test="table-group" class="position-relative">
        <div :class="stickyId" class="sticky-group">
          <div v-if="title" group="tablegroups" class="draggable-item"
               data-draggable-mirror="{&quot;xAxis&quot;:false}">
            <div class="table-row-template d-flex align-items-stretch"
                 style="min-height: var(--group-title-height)">
              <div class="shadow-area"></div>
              <div class="header-wrapper" :class="{'header-additional-column': showAddColumn}" @click.prevent="() => toggleGroup(!isShowTable)">
                <a class="header-content position-sticky d-flex align-items-center">
                  <itf-button squircle icon small secondary class="collapse-arrow">
                    <itf-icon :name="isShowTable ? 'chevron_down' : 'chevron_right'"/>
                  </itf-button>
                  <span class="d-flex align-items-center line-overflow group-header-value text-primary"
                        data-test="group-value-group-label-value">
                    <slot name="group-title" :rows="rows" :title="title" :collapsed="!isShowTable">{{ title }}</slot>
                  </span>
                </a>
              </div>
            </div>
          </div>

          <itf-table-header
            v-if="isShowTable"
            :visible-header="showHeader"
            :columns="visibleColumns"
            @sort:columns="onColumnsSorted"
            :column-resizing="columnResizing"
            :column-sorting="columnSorting"
            :show-add-column="showAddColumn"
            :show-actions="showActions"
            :id-property="idProperty"
            :rows="rows"
            :schema="schema"
            :editable="editable"
            :no-column-menu="noColumnMenu"
            :no-select-all="noSelectAll"
            :selected-ids="selectedIds"
            :indicatorType="indicatorType"
            :sorting.sync="_sorting"
            @update:selectedIds="$emit('update:selectedIds', $event)"
            @update:columns="$emit('update:columns', $event)"
            @filter="$emit('filter', $event)"
            @add-column="$emit('add-column', $event)"
          >
            <template v-for="(_, name) in $slots" #[name]="slotData">
              <slot :name="name" v-bind="slotData || {}"/>
            </template>
            <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
              <slot :name="name" v-bind="slotData || {}"/>
            </template>
          </itf-table-header>
        </div>

        <!-- Сама таблиця -->
        <div v-if="isShowTable">
          <itf-table-body
            @update="$emit('update', $event)"
            @row-click="$emit('row-click', $event)"
            :id-property="idProperty"
            :subrows-property="subrowsProperty"
            :divider-property="dividerProperty"
            :rows="rows"
            :editable="editable"
            :currency="currency"
            :currencies="currencies"
            :columns="visibleColumns"
            :no-select-all="noSelectAll"
            :selected-ids="selectedIds"
            :indicatorType="indicatorType"
            :expanded-all="expandedAll"
            :striped="striped"
            :show-add-column="showAddColumn"
            :show-actions="showActions"
            :expanded-ids="expandedIds"
            :css-property="cssProperty"
            :editable-property="editableProperty"
            :active="active"
            @update:expanded-ids="$emit('update:expanded-ids', $event)"
          >
            <template v-for="(_, name) in $slots" #[name]="slotData">
              <slot :name="name" v-bind="slotData || {}"/>
            </template>
            <template v-for="(_, name) in $scopedSlots" #[name]="slotData">
              <slot :name="name" v-bind="slotData || {}"/>
            </template>
          </itf-table-body>
        </div>

        <!-- Лінія додати нову -->
        <div v-if="isShowTable && addNewRows"
             class="d-flex align-items-stretch">
          <div class="shadow-area"></div>
          <a href="" @click.prevent="$emit('new', title)" data-test="table-add-new-item"
             class="d-flex align-items-center flex-grow-1 table-add-new-item text-decoration-none">
            <span class="d-sticky d-flex align-items-center py-2 px-2">
              <itf-icon name="plus"/>
              <span>{{ newLabel }}</span>
            </span>
          </a>
        </div>

        <!-- Групування -->
        <div v-if="isShowTable && showSummary" class="table-row-template d-flex align-items-stretch table-summary" :class="{'table-summary-persist': persistSummary}">
          <div class="shadow-area"></div>

          <div class="table-summary-columns d-flex tw-flex-row align-items-center w-100 flex-grow-1">
            <span
              v-for="(column, n) in visibleColumns"
              v-if="column.visible !== false"
              :key="n"
              :data-column="n"
              class="position-relative line-overflow px-1"
              :style="`width: ${column.width}px; max-width: ${column.width}px;`">
              <itf-dropdown append-to-context text right @open="persistSummary = true" @close="persistSummary = false" autoclose="outside">
                <template #button>
                  <span data-test="summary-column" class="invisible-summary d-flex align-items-center justify-content-end flex-auto">
                    <span v-if="column.calculate === 'none' || !column.calculate" class="table-summary-column summary-placeholder align-items-center justify-content-center">
                      {{$t('components.table.calculate')}}
                      <itf-icon name="chevron_down" />
                    </span>
                    <span v-else class="text-truncate">
                      <span class="summary-text text-uppercase pe-2">{{getCalculateMethodTitle(column.calculate)}}</span>
                      <slot :name="`summary.${column.property}`" :value="getCalculateMethodValue(column.calculate, column)" :raw="!column.calculate.includes('count') && !column.calculate.includes('percent')">
                        <span>{{getCalculateMethodValue(column.calculate, column)}}</span>
                      </slot>
                    </span>
                  </span>
                </template>

                <div v-for="(method, m) in calculateMethods" :key="method.id">
                  <a class="dropdown-item d-flex align-items-center"  href="javascript:;" @click="selectSummary(method, n)">
                    {{method.title}}
                  </a>
                </div>
              </itf-dropdown>
            </span>
          </div>
        </div>
      </div>
    </div>
  </div>

</template>
<style lang="scss">
.itf-table-group {
  flex-direction: column;
  min-width: 100%;
  display: flex;
  width: fit-content;
  //margin-top: 20px;
  //margin-bottom: 20px ;

  &.no-indicator {
    .shadow-area + .table-view-header-value, .table-item-inner {
      border-left: var(--itf-table-border-base-width) solid var(--itf-table-border-color);
    }
  }

  .preline {
    display: flex;
    align-items: center;
    height: 32px;

    &.over .line {
      width: 100%;
      border-bottom: 4px solid rgb(71 190 255 / 1);
    }
  }
  .sticky-group {
    transition: transform 0.02s;
  }
  .sticky-group.sticky {
    z-index: 5;

    &:before {
      content: '';
      position: absolute;
      left: 0;
      right: 0;
      top: -50px;
      height: 50px;
      background: var(--bs-body-bg);
    }
  }

  .table-group-wrapper {
    display: flex;
    //height: calc(var(--group-title-height) + var(--table-small-row-size) * 1 + var(--row-count) * var(--table-row-height));
  }

  .shadow-area {
    z-index: 4;
    //height: 100%;
    width: var(--shadow-area-width);
    justify-content: center;
    align-items: center;
    gap: 4px;
    display: flex;
    position: -webkit-sticky;
    position: sticky;
    left: 0;
    background: var(--bs-body-bg);
    //border-right: 1px solid var(--bs-border-color);
  }

  .header-wrapper:not(.collapsed *) {
    flex-grow: 1;
    border-bottom-right-radius: 0 !important;
    border-bottom-left-radius: 0 !important;
  }

  .header-wrapper {
    cursor: pointer;
    background-color: var(--bs-body-bg);
    left: var(--shadow-area-width);
    align-items: center;
    display: flex;
    position: -webkit-sticky;
    position: sticky;
    border-radius: 0.1875rem;
    font-weight: 500;
    font-size: 1.25rem;
    border-left: 0;
    border-bottom: 0;
    //border-right: 1px solid var(--bs-border-color);

    &.header-additional-column {
      border-radius: 0;
    }
    &:hover {
      //background: var(--itf-table-hover-bg); // видно, що група не на всю ширину коли є нижній скролінг
    }
  }

  .header-content {
    text-decoration: none;
  }
  .header-content:not(.draggable-mirror *) {
    left: var(--shadow-area-width);
    //padding-left: 0.75rem;
    padding-right: 0.75rem;
    gap: 1rem;
    align-items: center;
    position: sticky;
    display: flex;
  }

  .table-group-item-count {
    padding: 0.125rem 0.5rem;
    //background-color: rgb(250 251 252 / 1);
    border-radius: 0.1875rem;
    font-weight: normal;
    font-size: 1rem;
  }

  .vue-recycle-scroller__item-wrapper {
    overflow: visible;
  }

  .table-row-template {
    min-height: var(--table-small-row-size);
  }

  .table-add-new-item {
    margin-top: -12px;
    border-bottom: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
    outline: none;
    border-bottom-left-radius: var(--itf-table-table-border-radius);
    border-bottom-right-radius: var(--itf-table-table-border-radius);
    border-right: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);

    > .d-sticky {
      border-left: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
      border-bottom-left-radius: var(--itf-table-table-border-radius);
    }

    & > span {
      left: var(--shadow-area-width);
      position: sticky;
      padding-left: var(--shadow-area-width);
      //border-left: var(--itf-table-border-base-width) solid var(--itf-table-border-base-color);
      height: 100%;
    }
    &:hover, &:active {
      background: var(--itf-table-hover-bg);
    }
  }

  .sticky-group {
    top: 0px;
    position: sticky;
    z-index: 10;

    & > .draggable-item {
      margin-bottom: 8px;
    }
    .collapse-arrow {
      padding: 0;

      &:after {
        display: none;
      }
    }
  }
  .table-summary {
    .shadow-area {
      border-right: 0;
      min-width: var(--itf-table-min-width);
    }
    .table-summary-columns {
      padding-right: .5rem;
      text-align: right;
    }
    .table-summary-column {
      opacity: 0.05;
      font-size: .85rem;
      padding-right: .25rem;
    }
    .summary-text {
      color: var(--itf-table-summary-text);
    }
    &.table-summary-persist .table-summary-column,
    &:hover .table-summary-column {
      opacity: 1;
    }
  }
}
</style>
<script>
import get from 'lodash/get';
import sortBy from 'lodash/sortBy';
import uniq from "lodash/uniq";
import { round } from "../../helpers/formatters";
import {Vue, Component, Prop, Watch, PropSync} from 'vue-property-decorator';
import itfDropdown from '../dropdown/Dropdown.vue';
import itfButton from '../button/Button.vue';
import itfIcon from '../icon/Icon.vue';
import itfTableBody from './TableBody.vue';
import itfTableHeader from './TableHeader.vue';
import Sticky from "./sticky";
import { getIsMobileView } from "./mobile";

function getNumber(item, prop) {
  const num = Number(get(item, prop));
  return Number.isNaN(num) ? 0 : num;
}

export default @Component({
  name: 'itfTableGroup',
  components: {
    itfButton,
    itfIcon,
    itfTableBody,
    itfDropdown,
    itfTableHeader
  }
})
class itfTableGroup extends Vue {
  @Prop() columns;
  @Prop() rows;
  @Prop() selectedIds;
  @Prop() title;
  @Prop() idProperty;
  @Prop() subrowsProperty;
  @Prop() dividerProperty;
  @Prop() currency;
  @Prop() currencies;
  @Prop() active;
  @Prop(Boolean) showGrouping;
  @Prop(Boolean) showSummary;
  @Prop(Boolean) addNewRows;
  @Prop(Boolean) columnSorting;
  @Prop(Boolean) columnResizing;
  @Prop(Boolean) showAddColumn;
  @Prop(Boolean) showActions;
  @Prop(Boolean) showHeader;
  @Prop(Boolean) noColumnMenu;
  @Prop(Boolean) noSelectAll;
  @Prop(Boolean) editable;
  @Prop() editableProperty;
  @Prop(Boolean) expandedAll;
  @Prop(Boolean) striped;
  @Prop(Boolean) stickyHeader;
  @Prop() indicatorWidth;
  @Prop() shadowWidth;
  @Prop() cssProperty;
  @PropSync('sorting') _sorting;
  @Prop({ type: String, default: null }) indicatorType;
  @Prop({type: String, default: function() { return this.$t('components.table.new'); } }) newLabel;
  @Prop({type: Object, default: () => ({})}) schema;
  @Prop() expandedIds;
  @Prop() collapsedGroupIds;

  persistSummary = false;

  get isShowTable() {
    return typeof this.collapsedGroupIds !== 'undefined' ? !this.collapsedGroupIds.includes(this.title) : true;
  }

  get visibleColumns() {
    let list = this.columns;
    list = sortBy(list, (column) => column.index);
    let left = Number(this.shadowWidth) + (this.indicatorType === 'none' ? 1 : Math.max(Number(this.indicatorWidth), 16)); // sum of first 2 cells
    const pinned = list.filter((column) => column.pinned && column.visible !== false);
    list = list.map((column, index) => {
      const item = {...column};
      item.left = (item.pinned && !getIsMobileView() && item.visible !== false) ? left : 0;
      left = (item.pinned && !getIsMobileView() && item.visible !== false) ? left + column.width : left;
      item.lastPinned = index === pinned.length - 1;
      return item
    });
    return list;
  }

  onColumnsSorted(columns) {
    this.$emit('sort:columns', columns);
    this.$emit('update:columns', columns);
  }

  toggleGroup(val) {
    let expanded = this.collapsedGroupIds ? [...this.collapsedGroupIds] : [];
    if (!val) {
      if (!expanded.includes(this.title)) {
        expanded.push(this.title);
      }
    } else {
      expanded = expanded.filter(id => id !== this.title);
    }
    console.info(expanded, this.title, val);
    this.$emit('update:collapsed-group-ids', expanded);
  }

  get stickyId() {
    return `sticky-group-${this._uid}`;
  }

  mounted() {
    if (this.stickyHeader) {
      this.sticky = new Sticky(`.${this.stickyId}`, {
        wrap: true,
        stickyClass: 'sticky',
      });
    }
  }

  selectSummary(method, index) {
    const columns = [...this.columns];
    columns[index].calculate = method.id;
    this.$emit('update:columns', columns);
  }

  get calculateMethods() {
    return [
      { id: 'none', title: this.$t('components.table.calculateNone') },
      { id: 'total', title: this.$t('components.table.calculateTotal'), summary: 'Total', func: (rows, column) => round(rows.reduce((acc, row) => acc + (getNumber(row, column.property)), 0)) },
      { id: 'average', title: this.$t('components.table.calculateAverage'), summary: 'Average', func: (rows, column) => {
          const sum = rows.reduce((acc, row) => acc + (getNumber(row, column.property)), 0);
          return round(sum / rows.length, 3);
        } },
      { id: 'min', title: this.$t('components.table.calculateMin'), summary: 'Min', func: (rows, column) => Math.min(...rows.map(row => getNumber(row, column.property))) },
      { id: 'max', title: this.$t('components.table.calculateMax'), summary: 'Max', func: (rows, column) => Math.max(...rows.map(row => getNumber(row, column.property))) },
      { id: 'countAll', title: this.$t('components.table.calculateCountAll'), summary: 'Count', func: (rows) => rows.length },
      { id: 'countValues', title: this.$t('components.table.calculateCountValues'), summary: 'Values', func: (rows, column) => rows.filter(row => !!get(row, column.property)).length },
      { id: 'countUniqueValues', title: this.$t('components.table.calculateCountUniqueValues'), summary: 'Unique', func: (rows, column) => uniq(rows.map(row => get(row, column.property)).filter(item => !!item)).length },
      { id: 'countEmpty', title: this.$t('components.table.calculateCountEmpty'), summary: 'Empty', func: (rows, column) => rows.filter(row => !get(row, column.property)).length },
      { id: 'countNotEmpty', title: this.$t('components.table.calculateCountNotEmpty'), summary: 'Not Empty', func: (rows, column) => rows.filter(row => !!get(row, column.property)).length },
      { id: 'percentEmpty', title: this.$t('components.table.calculatePercentEmpty'), summary: 'Empty', func: (rows, column) => {
          const empty = rows.filter(row => !get(row, column.property)).length;
          return round(empty / rows.length * 100, 3) + '%';
        } },
      { id: 'percentNotEmpty', title: this.$t('components.table.calculatePercentNotEmpty'), summary: 'Not Empty', func: (rows, column) => {
          const notEmpty = rows.filter(row => !!get(row, column.property)).length;
          return round(notEmpty / rows.length * 100, 3) + '%';
        } },
    ];
  }

  getCalculateMethodTitle(methodName) {
    return this.calculateMethods.find(method => method.id === methodName)?.summary;
  }

  getCalculateMethodValue(methodName, column) {
    const method = this.calculateMethods.find(method => method.id === methodName);
    return method?.func ? method.func(this.rows, column) : '';
  }
}
</script>
