<template>
  <div>
    <div class="px-1">
      <div class="facets-filter-header">
        <div v-if="title">{{title}}</div>
      </div>

      <itf-text-field small v-model="query" class="mb-2" :placeholder="$t('components.filter.search')" clearable />

      <div class="d-flex justify-content-between small mb-2">
        <a v-if="isSelectedAll" href="" @click.stop.prevent="onSelectAll(false)">{{$t('components.filter.deselectAll')}}</a>
        <a v-else href="" @click.stop.prevent="onSelectAll(true)">{{$t('components.filter.selectAll')}}</a>

        <span class="text-muted" v-if="!isHasSelected" href="" @click.stop.prevent="onShowSelected(true)">{{$t('components.filter.showSelected')}}</span>
        <a v-else-if="!isShowSelected" href="" @click.stop.prevent="onShowSelected(true)">{{$t('components.filter.showSelected')}}</a>
        <a v-else href="" @click.stop.prevent="onShowSelected(false)">{{$t('components.filter.showAll')}}</a>
      </div>
      <div v-if="!mappedValues.length">
        <div class="text-muted text-center py-4">{{ $t('components.filter.noResults') }}</div>
      </div>
    </div>
    <div class="facets-list">
      <div v-for="(val, g) of groupedList" :key="g" :style="{paddingLeft: `${((val.level || 0) + 0.5) * 1}rem`}"
           class="dropdown-item" :class="{'active': val.isSelected, 'active': isGroupSelected(val)}" @click="onFilterClick(val)">
        <span class="facet-name text-dark d-flex align-items-center">
          <itf-checkbox ungrouped :value="val.isSelected" class="m-0" />
          <itf-icon new v-if="val.isGroup && groupIcon" :name="groupIcon" class="me-1" />
          <div class="w-100 text-truncate">{{ val.label }} <span v-if="val.description" class="small"><br/>{{ val.description }}</span></div>
        </span>
        <span v-if="val.count" class="facet-stat">
          {{ val.count }}
          <span class="facet-bar"><span :style="{'--bar-width': `${getPercent(val)}%`}" class="facet-bar-progress" /></span>
        </span>
      </div>
    </div>

    <itf-button default class="mt-1" v-if="hasMore" small block @click="toggleMore">
      <span v-if="showMore">{{ $t('components.filter.hideMore', { count: visibleList.length }) }}</span>
      <span v-else>{{ $t('components.filter.showMore', { count: visibleList.length }) }}</span>
    </itf-button>
  </div>
</template>
<style lang="scss" scoped>
.facets-filter-header {
  border-bottom: 1px solid var(--bs-border-color-translucent);
  color: #A5A5A9;
  padding: 0 0.75rem .5rem;
  margin: 0 -.75rem .75rem;
}
.facets-list {
  max-height: 50vh;
  overflow: auto;
}
.dropdown-item {
  --bs-dropdown-link-active-bg: rgba(var(--bs-primary-rgb), .25);

  cursor: pointer;
  display: inline-flex;
  -webkit-box-align: center;
  align-items: center;
  -webkit-box-pack: justify;
  justify-content: space-between;
  position: relative;
  box-sizing: border-box;
  min-height: 1.75rem;
  width: 100%;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 400;
  white-space: normal;
  user-select: none;
  border-radius: 0.25rem;
  border-width: 1px;
  border-style: solid;
  border-color: transparent;
  border-image: initial;
  transition: none 0s ease 0s;
  margin: 1px 0;
  &.active {
    .facet-bar-progress {
      background-color: var(--bs-blue);
    }
  }
  .facet-name {
    min-width: 0;
    text-align: left;
    line-height: 100%;
    white-space: nowrap;

    .itf-checkbox {
      min-height: 1.25rem;
    }
  }
  .facet-stat {
    display: flex;
    -webkit-box-align: center;
    align-items: center;
    margin-left: 0.25rem;
  }
  .facet-bar {
    display: inline-block;
    margin-left: 0.5rem;
    width: 60px;
  }
  .facet-bar-progress {
    display: block;
    width: var(--bar-width);
    min-width: 5px;
    height: 10px;
    background-color: rgba(var(--bs-blue-rgb), 50%);
    transition: width 0.3s ease 0s;
  }
}
</style>
<script>
import uniq from 'lodash/uniq';
import sortBy from 'lodash/sortBy';
import groupBy from 'lodash/groupBy';
import { Vue, Prop, Model, Component } from 'vue-property-decorator';
import itfTextField from '../text-field/TextField.vue';
import itfIcon from '../icon/Icon';
import itfButton from '../button/Button';
import itfCheckbox from '../checkbox/Checkbox.vue';

export default @Component({
  name: 'FilterFacetsList',
  components: {
    itfCheckbox,
    itfIcon,
    itfButton,
    itfTextField
  }
})
class FilterFacetsList extends Vue {
  @Model('input') value;
  @Prop() items;
  @Prop() item;
  @Prop() total;
  @Prop() options;
  @Prop({ type: Number, default: 5 }) limit;
  @Prop(Boolean) multiple;
  @Prop(Boolean) showAll;
  @Prop(String) title;

  query = '';
  showMore = false;
  isShowSelected = false;

  toggleMore() {
    this.showMore = !this.showMore;
  }

  get groupIcon() {
    return this.options?.groupIcon;
  }

  get flatList() {
    return treeToFlat(this.items || []);

    function getIdsDeep(items, mapFunc) {
      return (items ?? []).reduce((acc, item) => {
        const id = mapFunc(item);
        if (id) {
          acc.push(id);
        }
        if (item.items && item.items.length) {
          acc.push(...getIdsDeep(item.items, mapFunc));
        }
        return acc;
      }, []);
    }
    function treeToFlat(items, level = 0) {
      return (items ?? []).reduce((acc, item) => {
        acc.push({
          ...item,
          level,
          ids: [item.isGroup ? `g:${item.value}` : item.value].concat(
            getIdsDeep(item.items, (item) => item.isGroup ? `g:${item.value}` : item.value)
          )
            .filter(Boolean),
        });
        if (item.items && item.items.length) {
          // acc.push({ ...item, group: item.label, level });
          acc.push(...treeToFlat(item.items, level + 1));
        }
        return acc;
      }, []);
    }
  }

  get hasMore() {
    if (this.showAll) {
      return false;
    }
    return this.visibleList.length > this.limit;
  }

  get hasGroups() {
    const groups = uniq(this.flatList && this.flatList.map(item => item.group).filter(Boolean));
    return groups.length > 1
  }

  isGroupSelected(val) {
    return (val.ids ?? []).every(id => this.value.includes(`${id}`));
  }

  groupSelected(value, ids) {
    let newVal = this.value ? [...Array.isArray(this.value) ? this.value : [this.value]] : [];
    console.info(value, ids);
    if (value) {
      ids.forEach((id) => {
        const itemValue = `${id}`;
        if (!newVal.includes(itemValue)) {
          newVal.push(itemValue);
        }
      });
    } else {
      ids.forEach((id) => {
        const itemValue = `${id}`;
        newVal = newVal.filter(val => val !== itemValue);
      });
    }
    this.$emit('input', this.multiple ? newVal : (newVal.length > 0 ? newVal[0] : null));
  }

  get visibleList() {
    let list = this.flatList.map(val => {
      const isSelected = this.multiple
        ? Array.isArray(this.value) && this.value.map(String).includes(`${val.value}`)
        : `${this.value}` === `${val.value}`;

      return { ...val, isSelected };
    });
    if (this.query) {
      list = list.filter((val) => val.label.toLowerCase().includes(this.query.toLowerCase()));
    }
    if (this.isShowSelected) {
      return list.filter((val) => val.isSelected);
    }
    return this.hasGroups ? sortBy(list, (item) => item.group || item.label) : list;//sortBy(list, (item) => this.hasGroups ? item.group || item.label : item.label);
  }

  get groupedList() {
    if (!this.hasGroups) {
      return this.mappedValues;
    }
    const groups = groupBy(this.mappedValues, (item) => item.group || '');
    return Object.entries(groups).reduce((acc, [group, items]) => [...acc, { label: group, isGroup: true }, ...(items.map(item => ({ ...item, level: 1 })))], []);
  }

  get mappedValues() {
    const list = this.visibleList;
    if (!this.showMore && !this.showAll) {
      return list.slice(0, this.limit);
    }
    return list;
  }

  getPercent(item) {
    return this.total ? Math.round((item.count / this.total) * 100) : 0;
  }

  onFilterClick(val) {
    if (val.isGroup) {
      this.groupSelected(!val.isSelected, val.ids);
      return;
    }
    const value = `${val.value}`;
    if (!this.multiple) {
      return this.$emit('input', `${this.value}` === value ? null : value);
    }
    const newVal = [...Array.isArray(this.value) ? [...this.value] : []].map((s) => s.toString());
    if (newVal.includes(value)) {
      newVal.splice(newVal.indexOf(value), 1);
    } else {
      newVal.push(value);
    }
    this.$emit('input', newVal);
  }

  get isSelectedAll() {
    return this.mappedValues.every(o => o.isSelected);
  }

  onSelectAll(isSelect = false) {
    if (isSelect) {
      this.$emit('input', this.visibleList.map((val) => `${val.value}`));
    } else {
      this.$emit('input', []);
    }
    this.isShowSelected = false;
  }

  get isHasSelected() {
    return this.value && this.value.length > 0 && !this.query; // тільки коли не пошук
  }

  onShowSelected(isShow = false) {
    if (!this.value.length && isShow) { // не показувати, якщо нічого не вибрано
      return;
    }
    this.isShowSelected = isShow;
  }
}
</script>
