import { Component, Emit, Prop, Watch, PropSync } from 'vue-property-decorator';
import Vue from 'vue';
import BaseSearchBar from '@components/common/base-search-bar/index.vue';
import { QPagination } from '@/models/models-ui';
import QColumn from '@/types/QColumn';
import omit from 'lodash/omit';
import get from 'lodash/get';
import pick from 'lodash/pick';
import { TablePagination } from '@models/base/TablePagination';

@Component({
  components: { BaseSearchBar },
})
export default class BaseTable extends Vue {
  @Prop({
    type: Boolean,
    default: false,
  })
  showToggleMy?: boolean;

  @Prop() useSearch?: boolean;
  @Prop({ default: false }) hideRefresh?: boolean;
  @Prop() rowsHandler?: any;
  @Prop() rowsPerPageOptions?: any[];
  @Prop({ default: '' }) value?: string;
  @Prop() columns?: QColumn[];
  @Prop() data?: any[];
  @Prop() visibleColumns?: any[];
  @Prop() pagination?: QPagination | null;
  @Prop() loading?: boolean;
  @Prop() title?: string;
  @Prop({
    default: false,
  })
  binarySort?: boolean;

  @PropSync('onlyMy') onlyMyCast?: boolean;

  @Prop() selection?: string;
  @Prop({ type: Boolean, default: false }) saveQuery?: boolean;

  @PropSync('selected', {
    default: () => [],
  })
  syncedSelected?: any[];

  @Watch('value', { immediate: true })
  valueHandler(val: string): void {
    this.inputSearch = val;
  }

  @Watch('inputSearch')
  inputSearchCastHandler(val: string): void {
    this.$emit('input', val);
  }

  @Watch('onlyMy')
  showToggleMyHandler(val: boolean): void {
    this.$emit('changeToggleMy', { onlyMy: val, page: 1 });
    this.$router.push({ query: { ...this.$route.query, onlyMy: val.toString(), page: "1" } });
  }

  private inputSearch = '';

  private get rowsPerPageOptionsCustom(): any[] {
    return this.rowsPerPageOptions || [3, 5, 10, 15, 20, 25, 50];
  }

  private paginationLabelCustom(pagination: TablePagination): string {
    const page = pagination.page;
    const rowsPerPage = pagination.rowsPerPage;
    const rowsNumber = pagination.rowsNumber || Number(this.data?.length);
    const firstNumber = (page - 1) * rowsPerPage + rowsPerPage;

    return `${(page - 1) * rowsPerPage + 1} - ${
      firstNumber < rowsNumber ? firstNumber : rowsNumber
    } ${this.$t('base.of').toString().toLowerCase()} ${rowsNumber}`;
  }

  private crop(field: any, start = 0, end = 2): [] {
    return field.slice(start, end);
  }

  private difference(field: any, start = 2): [] {
    return this.crop(field, start, field.length);
  }

  private field(row: any, name: string, item: any): any {
    const column: any = this.columns?.find((column) => column.name === name);

    let field: any;

    if (item) {
      field = item;
    } else if (this.has(column, 'field')) {
      if (typeof column.field === 'function') {
        field = column.field(row);
      } else if (typeof column.field === 'string') {
        field = get(
          {
            row,
          },
          `row.${column.field}`
        );
      }
    }

    return field;
  }

  private format(row: any, name: string, item?: any): any {
    const column: any = this.columns?.find((column) => column.name === name);

    const field: any = this.field(row, name, item);

    let format: any = field;

    if (this.has(column, 'formatField')) {
      if (Array.isArray(format)) {
        format = format.map((item) => {
          const value = get({ item }, `item.${column.formatField}`, '');
          const defaultValue = get(
            { item },
            `item.${column.defaultFormatField}`,
            ''
          );
          return value || defaultValue;
        });
      } else {
        const value = get({ format }, `format.${column.formatField}`, '');
        const defaultValue = get(
          { format },
          `format.${column.defaultFormatField}`,
          ''
        );
        format = value || defaultValue;
      }
    } else if (this.has(column, 'format')) {
      format = column.format(field);
    }

    return format;
  }

  private handler(ev: MouseEvent, row: any, name: string, item: any): void {
    const column: any = this.columns?.find((column) => column.name === name);

    const field: any = this.field(row, name, item);

    column.handler(
      this.has(column, 'handlerField')
        ? get(
            {
              field,
            },
            `field.${column.handlerField}`
          )
        : field,
      {
        targetBlank: ev.metaKey || ev.ctrlKey,
      }
    );
  }

  private has(column: any, name: string): any {
    return !!get(
      {
        column,
      },
      `column.${name}`
    );
  }

  private isArray(row: any, name: string): boolean {
    return Array.isArray(this.format(row, name));
  }

  private rowsHandlerCast(row: any): void {
    if (!!this.rowsHandler && typeof this.rowsHandler === 'function') {
      this.rowsHandler(row);
    }
  }

  @Emit('requestTable')
  requestHandler(value: any) {
    // QTable requestServerInteraction
    // Обработка данного события сделана с изменением имени события request -> requestTable, из-за того,
    // что обычный request всплывает несколько раз для случая, когда мы перешли на каку-то страницу поиска
    // и изменили фильтр

    const paramsQuery: any = pick(value.pagination, [
      'page',
      'sortBy',
      'descending',
      'rowsPerPage',
    ]);

    const routeQuery = { ...this.$route.query };

    Object.keys(paramsQuery).forEach((keyQuery: string) => {
      if (paramsQuery[keyQuery] === null) {
        delete paramsQuery[keyQuery];
        delete routeQuery[keyQuery];
      }
    });

    if (this.saveQuery) {
      this.$router.push({
        query: {
          ...routeQuery,
          ...paramsQuery,
        },
      });
    }
  }

  @Emit('update')
  updateHandler() {
    //
  }

  @Emit('update:pagination')
  paginationHandler() {
    //
  }

  @Emit('search')
  searchHandler() {
    //
  }

  @Emit('update:selected')
  selectedHandler() {
    //
  }

  @Emit('query')
  queryHandler() {
    //
  }
}
