<template>

  <div v-loading="loading || loadingData" class="flex-grow-1 w-100 d-flex flex-column">
    <itf-filter-panel
      :search-placeholder="searchPlaceholder"
      search
      :visible="!noFilters"
      :filters-only="filtersOnly"
      ref="filters"
      :mini="panel.isMultiple()"
      class="py-2 px-3"
      :endpoint="filtersEndpoint"
      :panel="panel"
      v-model="filter"
      @loaded="onFilterSet($event, true)"
      @change="onFilterSet($event, false)"
    >
      <template #after-filter-btn>
        <itf-dropdown v-if="$refs.table && schema" shadow append-to-context :button-options="{ default: true, icon: true }" class="h-100" autoclose="outside">
          <template #button>
            <itf-icon new name="table-view" />
          </template>
          <div class="dropdown-header">
            {{ $t('components.table.columns') }}
          </div>
          <a v-for="(property, n) of schema.properties" :key="n" href="" @click.stop.prevent="$refs.table.toggleVisibility(property.property)" class="dropdown-item justify-content-between d-flex gap-3">
            <div class="d-flex align-items-center gap-1">
              <itf-icon v-if="property.icon" :size="24" new :name="property.icon" />
              {{getTitle(property.title)}}
            </div>

            <itf-icon v-if="$refs.table.getColumnVisibility(property.property)" new :size="24" name="eye-open" />
            <itf-icon v-else new name="eye-close" />
          </a>
          <div class="dropdown-header">
            {{ $t('components.table.actions') }}
          </div>
          <a href="" @click.stop.prevent="$refs.table.resetSettings()" class="dropdown-item justify-content-between d-flex gap-3">
            <div class="d-flex align-items-center gap-1">
              <itf-icon new :size="24" name="download" />
              {{ $t('components.table.resetTableSettings') }}
            </div>
          </a>
        </itf-dropdown>
      </template>
    </itf-filter-panel>

    <div class="flex-grow-1 px-3 d-flex flex-column">
      <div class="position-relative flex-grow-1">
        <itf-table
          ref="table"
          style="--shadow-area-width: 0px;"
          absolute
          striped
          clickable
          column-sorting
          column-resizing
          :indicator-type="indicatorType"
          class="permanent-checkboxes"
          :state-name="stateName"
          id-property="id"
          :rows="preparedItems"
          :schema="schema"
          :sorting="sorting"
          :active="activeIds"
          :show-actions="showActions"
          :indicator-width="indicatorWidth"
          :no-select-all="noSelectAll"
          v-model="selectedIds"
          @row-click="$emit('open', $event)"
          @update:sorting="updateSorting($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>
      </div>
    </div>

    <itf-pagination
      class="my-2 px-3"
      show-size
      :size="size"
      :items="preparedItems"
      :pages="countPages"
      :value="page"
      :totalCount="showTotalCount ? total : null"
      @input="updatePage($event)"
      @per-page="updateSizePerPage($event)"
    >
      <template #center>
        <slot name="pagination-center" />
      </template>
    </itf-pagination>
  </div>

</template>
<script>
import { Vue, ModelSync, Component, Prop, Inject } from 'vue-property-decorator';
import loading from '../../directives/loading';
import itfTable from '../table/Table2.vue';
import itfFilterPanel from '../filter/FilterPanel.vue';
import itfPagination from '../pagination/Pagination2.vue';
import itfTableBody from "../table/TableBody.vue";
import itfIcon from "../icon/Icon.vue";
import itfDropdown from "../dropdown/Dropdown.vue";

export default @Component({
  name: 'itfView',
  components: {
    itfDropdown, itfIcon,
    itfPagination,
    itfFilterPanel,
    itfTableBody,
    itfTable
  },
  directives: {
    loading
  }
})
class itfView extends Vue {
  @Inject({ default: null }) panelList;
  @ModelSync('value', 'input') selectedIds;

  @Prop({ type: Boolean }) loading;
  @Prop({ type: Boolean }) filtersOnly;
  @Prop({ type: Boolean }) noFilters;
  @Prop({ type: Array }) filters;
  @Prop({ type: Object, required: true }) schema;
  // @Prop({ default: 20 }) size;
  // @Prop({ default: 1 }) page;
  @Prop(String) defaultSorting;
  @Prop(String) endpoint;
  @Prop(String) filtersEndpoint;
  @Prop(String) itemsKey;
  @Prop(String) panelKey;
  @Prop(String) stateName;
  @Prop({ type: String, default: 'checkbox' }) indicatorType;
  @Prop({ type: String, default () { return this.$t('components.table.search'); } }) searchPlaceholder;
  @Prop() panel;
  @Prop() hardFilter; // встановлює жорсткий фільтр, наприклад, треба завжди показувати лише по контрагенту
  @Prop(Boolean) showActions;
  @Prop({ type: Array, default: () => [] }) disabledIds;
  @Prop({ default: 45 }) indicatorWidth;
  @Prop(Boolean) noSelectAll;
  @Prop({ type: Boolean, default: false }) showTotalCount;

  page = 1;
  total = 0;
  size = 20;
  sorting = 'id';
  items = [];
  filter = {};
  loadingData = false;
  activeIds = [];

  get preparedItems() {
    const disabledIdsSet = new Set(this.disabledIds);
    return this.items.map(item => ({ ...item, isDisabled: disabledIdsSet.has(item.id) }));
  }

  created() {
    const defaultSize = localStorage.getItem('sizePerPage') ?? 20;

    const { page, size, sorting } = this.panel.getPayload() ?? {};
    this.page = page ?? 1;
    this.size = size ?? defaultSize;
    this.sorting = sorting ?? this.defaultSorting;
  }

  mounted() {
    if (this.panelList && this.panelList.panelsStack && this.panelList.panelsStack.length && this.panelKey) {
      const updateIds = () => {
        this.activeIds = this.panelList.panelsStack.filter(p => p.type === this.panelKey).map(p => p.payload.id);
      };
      this.panelList.panelsStack[0].on('panels.changed', updateIds);
      updateIds();
    }
  }

  async loadData(reloadFilters = false) {
    if (!this.endpoint) {
      return;
    }
    if (reloadFilters) {
      this.loadFilters();
    }
    this.$emit('load', this.filter);
    this.loadingData = true;
    await this.$try(async () => {
      const res = await this.$axios.$get(this.endpoint, {
        preventRaceCondition: true,
        params: {
          ...Object.assign(this.filter ?? {}, this.hardFilter ?? {}),
          page: this.page,
          size: this.size,
          sort: this.sorting
        }
      });
      this.selectedIds = [];
      this.items = res[this.itemsKey];
      this.page = res.meta.page;
      this.total = res.meta.total;
      this.size = res.meta.size;
      this.$emit('update:items', this.items);
      this.loadingData = false;
    }, () => {
      this.loadingData = false;
    });
    this.$emit('loaded', this.filter);
  }

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

  get countPages() {
    return Math.ceil(this.total / this.size) ?? 1;
  }

  updateSorting (val) {
    this.sorting = val;
    this.setPanelPayload({ sorting: val });
    this.loadData();
  }

  updatePage (val) {
    this.page = val;
    this.setPanelPayload({ page: val === 1 ? null : val });
    this.loadData();
  }

  updateSizePerPage (val) {
    this.page = 1;
    this.size = val;
    this.setPanelPayload({ page: null, size: val });
    this.loadData();
    localStorage.setItem('sizePerPage', val);
  }

  setPanelPayload(payload) {
    this.panel.setPayload(assignWithoutUndefined(this.panel.getPayload(), payload));

    function assignWithoutUndefined(...sources) {
      const target = {};
      sources.forEach(source => {
        if (source && typeof source === 'object') {
          Object.entries(source).forEach(([key, value]) => {
            if (key === 'page' && value === null) {
              delete target[key];
            } else if (value !== undefined) {
              target[key] = value;
            }
          });
        }
      });
      return target;
    }
  }

  onFilterSet(filter, keepPage = false) {
    if (keepPage) {
      // при завантаженні сторінки не потрібно скидувати сторінку
      this.setPanelPayload({ ...filter });
    } else {
      this.page = 1;
      this.setPanelPayload({ ...filter, page: null });
    }
    this.loadData();
  }

  loadFilters() {
    if (this.filtersEndpoint) {
      this.$refs.filters?.loadData();
    }
  }
}
</script>
