import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
import { QSelect } from 'quasar';
import { ReferenceBooksItemOption } from '@components/common/reference-book-item/index';
import has from 'lodash/has';
import isEqual from 'lodash/isEqual';

function concatUniq<T, E>(arr: T, val: E) {
  const array = Array.isArray(arr) ? arr.slice() : !arr ? [] : [String(arr)];
  if (!array.includes(val)) array.push(val);
  return array;
}
@Component({
  components: {
    QSelect,
  },
})
export default class DictionarySelectForComponents extends Vue {
  @Prop() dictionary: string;
  @Prop() value: any;
  @Prop() isReadonly: boolean;
  @Prop() valuesIn: string[];
  @Prop() optionValue: string;
  @Prop() allowedValues: any[];
  @Prop({ type: Boolean }) multiple: boolean;

  $refs!: {
    select: QSelect;
  };

  options: ReferenceBooksItemOption[] = [];
  originalOptions!: ReferenceBooksItemOption[];
  selectedGroupIndex: number | null = null;

  get hasAllowedOptionsList(): boolean {
    return Array.isArray(this.allowedValues) && this.allowedValues.length > 0;
  }

  get outValue() {
    if (this.selected === undefined) {
      return this.value;
    }
    return Array.isArray(this.selected)
      ? this.selected.map((e: any) => e[this.optionValue])
      : this.selected[this.optionValue];
  }

  get selected() {
    let selected = this.value || '';
    if (!Array.isArray(selected)) {
      selected = [selected];
    }
    const valuesIn = concatUniq(this.valuesIn, 'value');
    const options =
      this.selectedGroupIndex !== null &&
      has(this.options, [this.selectedGroupIndex, 'children'])
        ? (this.options[this.selectedGroupIndex]
            .children as ReferenceBooksItemOption[])
        : this.options;

    selected = options.filter((option) =>
      valuesIn.some((key: keyof typeof option) => {
        if (key in option) {
          const index = selected.indexOf(option[key]);
          const indexByValueObj = selected.findIndex((selectedIt: any) => {
            return (
              isEqual(selectedIt, option[key]) || selectedIt === option[key]
            );
          });
          if (index !== -1 || indexByValueObj !== -1) {
            selected.splice(index === -1 ? indexByValueObj : index, 1);
            return true;
          }
        }
        return false;
      })
    );
    return this.multiple ? selected.slice() : selected[0];
  }

  set selected(selected: any) {
    this.$emit('input', selected);
  }

  getStringValue(valueObj: { code: string; valueName: string } | string) {
    if (typeof valueObj === 'string') {
      return valueObj;
    }
    if (valueObj && valueObj.valueName === 'value') {
      return valueObj.code;
    }
    return valueObj;
  }

  dictionaryReady(options: ReferenceBooksItemOption[]) {
    this.options = this.hasAllowedOptionsList
      ? options.filter((el) => this.checkOption(el))
      : options;
    this.originalOptions = options;
    this.$refs.select?.refresh();
  }

  checkOption(el: ReferenceBooksItemOption): boolean {
    if (el.children) {
      // supports only 1 nested level
      return el.children.reduce(
        (acc: boolean, curr: ReferenceBooksItemOption) => {
          return acc || this.allowedValues.includes(curr.value);
        },
        false
      );
    } else {
      return this.allowedValues.includes(el.value);
    }
  }
}
