<template>

  <div class="itf-table2" :class="{
    'table-striped': striped,
    'table-absolute': absolute,
    'table-clickable': clickable,
    'permanent-checkboxes': selectedIds.length
  }" :style="{ '--indicator-area-width': `${indicatorType === 'none' ? 1 : indicatorWidth}px`, '--shadow-area-width': `${shadowWidth}px` }">
    <itf-notice-popout :visible="showGroupOperations" class="rounded-3 bg-black text-white">
      <div class="d-flex gap-2 ps-2 align-items-center small itf-table2_mass-operations">
        <slot name="group-operations-count">
          <div>{{$tc('components.table.selectedItems', selectedIds.length, { n: selectedIds.length })}}</div>
          <div class="opacity-50">•</div>
        </slot>
        <a href="" class="me-3 opacity-50 text-white text-decoration-none" @click.stop.prevent="selectedIds = []">{{$t('components.table.cancelSelected')}}</a>
        <div>
          <slot name="group-operations"></slot>
        </div>
      </div>
    </itf-notice-popout>
    <div class="scrollable scrollable-x">
      <itf-checkbox-group v-model="selectedIds" class="d-flex flex-column" style="min-width: 100%; width: max-content">
        <template v-for="(group, index) in groups">
          <div class="table-view-body">
            <itf-table-group
              :key="index"
              @update="$emit('update', { ...$event, group, groupIndex: index })"
              @row-click="$emit('row-click', $event)"
              :id-property="idProperty"
              :columns="columns"
              @update:columns="onColumnsUpdate"
              :rows="group.rows"
              :title="group.name"
              :selected-ids.sync="selectedIds"
              :add-new-rows="addNewRows"
              :shadow-width="shadowWidth"
              :column-sorting="columnSorting"
              :column-resizing="columnResizing"
              :show-grouping="showGrouping"
              :show-summary="showSummary"
              :show-add-column="showAddColumn"
              :show-actions="showActions"
              :show-header="!noHeader"
              :schema="schema"
              :editable="editable"
              :no-column-menu="noColumnMenu"
              :no-select-all="noSelectAll"
              :currencies="currencies"
              :currency="currency"
              :subrows-property="subrowsProperty"
              :divider-property="dividerProperty"
              :indicator-type="indicatorType"
              :expanded-all="expandedAll"
              :indicatorWidth="indicatorWidth"
              :striped="striped"
              :expanded-ids="expandedIds"
              :css-property="cssProperty"
              :sticky-header="stickyHeader"
              :editable-property="editableProperty"
              :sorting.sync="_sorting"
              :active="active"
              :new-label="newLabel"
              :collapsed-group-ids="collapsedGroupIds"
              @update:expanded-ids="$emit('update:expanded-ids', $event)"
              @update:collapsed-group-ids="$emit('update:collapsed-group-ids', $event)"
              @new="$emit('new', $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-group>
          </div>
        </template>
      </itf-checkbox-group>
    </div>
  </div>

</template>
<script>
import { Vue, Component, Prop, Watch, ModelSync, PropSync } from 'vue-property-decorator';
import itfCheckboxGroup from '../checkbox/CheckboxGroup.vue';
import itfButton from '../button/Button.vue';
import itfIcon from '../icon/Icon.vue';
import itfTableGroup from './TableGroup.vue';
import itfTableHeader from './TableHeader.vue';
import itfNoticePopout from '../popover/NoticePopout.vue';
import './table2.scss';

export default @Component({
  name: 'itfTable2',
  provide() {
    return { tableEl: this }; // do not use Provide from vue-property-decorator
  },
  components: {
    itfCheckboxGroup,
    itfTableHeader,
    itfButton,
    itfIcon,
    itfTableGroup,
    itfNoticePopout
  }
})
class itfTable2 extends Vue {
  // @Prop({ required: true, type: Array }) columns;
  @Prop({ required: true, type: Array }) rows;
  @Prop({ type: String, default: null }) groupBy;
  @Prop({ type: String, default: null }) idProperty;
  @Prop({ type: String, default: null }) cssProperty;
  @Prop({ type: String, default: null }) subrowsProperty;
  @Prop({ type: String, default: null }) dividerProperty;
  @Prop({ type: String, default: null }) editableProperty;
  @Prop({ default: null }) active;
  @Prop({ default: 45 }) indicatorWidth;
  @Prop({ default: 0 }) shadowWidth;
  @Prop({ type: String, default: null, validator: (val) => ['order', 'checkbox', 'toggle', 'property', 'none'].includes(val) }) indicatorType;
  @Prop({ type: String, default: null }) stateName; // save state to storage
  @Prop({ type: Object, default: () => ({}) }) schema;
  @ModelSync('value', 'input', { type: Array, default: () => ([]) }) selectedIds;
  @PropSync('sorting') _sorting;
  @Prop({ type: Array, default: () => [] }) expandedIds;
  @Prop({ type: Array }) collapsedGroupIds;
  @Prop() currency;
  @Prop() currencies;
  @Prop(Boolean) stickyHeader;
  @Prop(Boolean) addNewRows;
  @Prop(Boolean) columnSorting;
  @Prop(Boolean) columnResizing;
  @Prop(Boolean) showAddColumn;
  @Prop(Boolean) showGrouping;
  @Prop(Boolean) showActions;
  @Prop(Boolean) showSummary;
  @Prop(Boolean) noHeader;
  @Prop(Boolean) noColumnMenu;
  @Prop(Boolean) noSelectAll;
  @Prop(Boolean) editable;
  @Prop(Boolean) expandedAll;
  @Prop(Boolean) striped;
  @Prop(Boolean) absolute;
  @Prop(Boolean) clickable;
  @Prop({type: String, default: function() { return this.$t('components.table.new'); } }) newLabel;

  state = {
    selectedIds: [],
    columns: []
  };

  get showGroupOperations() {
    return !!(this.$slots['group-operations'] || this.$scopedSlots['group-operations']) && this.selectedIds.length > 0;
  }

  resetSettings() {
    const list = this.schema?.properties || [];
    this.state = {
      selectedIds: [],
      columns: [...list]
    };
    this.saveTableState();
    this.onSchemaUpdate();
  }

  getColumnVisibility(property) {
    return this.state.columns.find(i => i.property === property)?.visible ?? true;
  }

  toggleVisibility(property) {
    const column = this.state.columns.find(i => i.property === property);
    if (column) {
      column.visible = !column.visible;
    }
    this.onColumnsUpdate(this.columns);
  }

  getTableState() {
    const list = this.schema?.properties || [];
    let state = this.stateName ? JSON.parse(localStorage.getItem(this.stateKey) || 'null') : null;
    if (!state) {
      state = {
        selectedIds: [],
        columns: [...list]
      };
    }
    state.selectedIds = [];
    for (const column of list) {
      const stateColumnIndex = state.columns.findIndex(i => i.property === column.property);
      column.visible = (typeof column.visible === 'undefined') ? true : !!column.visible;
      if (stateColumnIndex === -1) {
        state.columns.push(column);
      } else {
        state.columns[stateColumnIndex] = { ...column, width: state.columns[stateColumnIndex].width, visible: state.columns[stateColumnIndex].visible };
      }
    }
    for (const column of state.columns) {
      const originColumn = list.find(i => i.property === column.property);
      if (!originColumn) {
        state.columns = state.columns.filter(i => i.property !== column.property);
      }
    }
    return state;
  }

  get stateKey() {
    return this.stateName ? `itf-table-${this.stateName}` : null;
  }

  saveTableState() {
    if (!this.stateName) {
      return;
    }
    const columns = this.state.columns.map((s) => ({ property: s.property, width: s.width, index: s.index, visible: s.visible }));
    localStorage.setItem(this.stateKey, JSON.stringify({ columns }));
  }

  mounted() {
    this.onSchemaUpdate();
  }

  @Watch('schema')
  onSchemaUpdate() {
    this.state = this.getTableState();
    this.selectedIds = this.state.selectedIds;
  }

  get columns() {
    return this.state?.columns || [];
  }

  get groups() {
    const { groupBy, rows } = this;
    const indexedRows = (rows || []).map((row, index) => ({ ...row, $index: index }));
    if (!groupBy || !indexedRows.length) {
      return [{ name: '', rows: indexedRows }]
    }
    const groups = indexedRows.reduce((acc, row) => {
      const group = row[groupBy];
      if (!acc[group]) {
        acc[group] = [];
      }
      acc[group].push(row);
      return acc;
    }, {});
    return Object.entries(groups).map(([name, rows]) => ({ name, rows }));
  }

  @Watch('selectedIds')
  onSelectedIdsUpdate(selectedIds) {
    this.state.selectedIds = selectedIds;
    this.saveTableState();
  }

  onColumnsUpdate(columns) {
    const pinned = [...columns.filter(i => i.pinned)];
    const unpinned = [...columns.filter(i => !i.pinned)];
    this.state.columns = [...pinned, ...unpinned].map((item, key) => ({ ...item, index: key }));
    this.$emit('update:columns', this.state.columns);
    this.saveTableState();
  }
}
</script>
