// @ts-nocheck
import { Component, Prop, Watch } from 'vue-property-decorator';
import { Field, Meta, Model, Schema } from '@devsun/eva-models';
import { QTable } from 'quasar';
import {
  ValidatedField,
  WidgetWrapper,
  FormGenerator,
  FormWidget,
} from '@devsun/form-generator/dist';
import { mixins } from 'vue-class-component';
import FormGeneratorWrapper from '@components/common/node-generator/FormGeneratorWrapper.vue';
import get from 'lodash/get';
import set from 'lodash/set';
import { v4 } from 'uuid';
import TableFillView from '@/components/common/node-generator/components-lib/form/custom/TableFillView.vue';

@Component({
  components: {
    FormGeneratorWrapper,
    TableFillView,
    WidgetWrapper,
    QTable,
  },
})
export default class TableFill extends mixins(ValidatedField, FormWidget) {
  @Prop({ default: false }) allowEdit: boolean;
  @Prop({ default: false }) allowDelete: boolean;
  @Prop({ default: () => [] }) cardBlackList: string[];
  @Prop({ default: () => [] }) cardLabelRenameList: object[];
  @Prop({ default: false }) excludeHeaderColFromCardBody: boolean;

  @Watch('items', { deep: true })
  itemsUpdated(items: Model.Base[]) {
    this.$refs.widget.inputEvents?.input(items);
  }

  checkFieldOnEmpty(fields): boolean {
    for (let key in fields) {
      const attr = this.attrs.find((item) => item.name === key);
      if (!attr?.props?.setDefault) {
        if (typeof fields[key] === 'object') {
          if (this.checkFieldOnEmpty(fields[key])) {
            return true;
          }
        } else if (fields[key]) {
          return true;
        }
      }
    }

    return false;
  }

  @Watch('tableFillModel', { deep: true })
  fieldsUpdate(fields): void {
    this.$root.$emit('TableFillUnSaveData', {
      label: this.fieldNode.label,
      unSaveData: this.checkFieldOnEmpty(fields),
    });
  }

  // subModel: Model.Base = null;
  items: Model.Base[] = [];
  newItem: Model.Base = {} as Model.Base;
  selectedItem: Model.Base = null as Model.Base;
  deleteItem: Model.Base = null as Model.Base;
  formGeneratorIsValid: boolean = true;
  deleteDialog: boolean = false;
  resetAttractions: boolean = false;

  get tableFillModel() {
    if (this.allowEdit && this.selectedItem) {
      return this.selectedItem;
    } else {
      return this.newItem;
    }
  }

  get attractionCode(): string {
    return this.subSchema?.name;
  }

  get attrs(): Field.Raw[] {
    return this.subSchema?.attrList;
  }

  get columns() {
    if (!this.attrs) return [];

    return this.attrs
      .map((attr) => {
        const field = attr?.props?.columnFieldPath
          ? (val) => get(val, attr?.props?.columnFieldPath as string)
          : attr.name;
        const label: string =
          this.cardLabelRenameList.find(
            (renameItem) => renameItem.name === attr.name
          )?.label || attr.label;

        return {
          name: attr.name,
          label,
          headerStyle: this.headerStyle,
          align: 'left',
          field,
        };
      })
      .filter((col) => !this.cardBlackList.includes(col.name));
  }

  get headerStyle(): Record<string, string> {
    return {
      whiteSpace: 'unset',
      verticalAlign: 'bottom',
    };
  }

  get includeColNames(): boolean {
    return (this.fieldNode?.rawAttrs?.props as Field.Raw['props'])
      ?.includeColNames;
  }

  get displayItems(): Model.Base[] {
    if (this.includeColNames) {
      return this.items.slice(1);
    }

    return this.items;
  }

  get isValid(): boolean {
    return this.formGeneratorIsValid;
  }

  get someFilled(): boolean {
    const keys = Object.keys(this.newItem);

    if (!keys.length) return false;

    return Object.values(this.newItem).some(Boolean);
  }

  get gridView(): boolean {
    return !!this.fieldNode?.rawAttrs?.props?.gridView;
  }

  get colNameItem(): Model.Base {
    return this.attrs?.reduce((item, nextAttr) => {
      item[nextAttr.name] = nextAttr?.props?.fullLabel || nextAttr.label;

      return item;
    }, {} as Model.Base);
  }

  get reference(): Meta.Reference {
    return this.fieldNode?.reference;
  }

  get linkedSchemas(): Schema.LinkedSchemaMap {
    return get(this.fieldNode, 'rootSchema.schema.linkedSchema');
  }

  get subSchema(): Partial<Schema.MetaClassSchemaRaw> {
    if (!this.reference) return;

    return get(
      this.linkedSchemas,
      `${this.reference.service}.${this.reference.entity}`
    );
  }

  get hasHeaderField(): boolean {
    return Boolean(
      this.subSchema?.attrList?.some((field) => field?.props?.useValueAsHeader)
    );
  }

  get headerFieldName(): string | null {
    if (!this.hasHeaderField) return null;

    const field = this.subSchema.attrList.find(
      (field) => field?.props?.useValueAsHeader
    );

    return field?.name || null;
  }

  getHeaderValue({ row, colsMap }): string {
    if (!row || !colsMap || !this.headerFieldName) return null;

    const fieldValueGetter = colsMap[this.headerFieldName]?.field;

    return typeof fieldValueGetter === 'function'
      ? fieldValueGetter(row)
      : row[this.headerFieldName];
  }

  initItem(newItem = {}) {
    const initItem = {};
    this.subSchema.attrList.forEach((attr) => {
      const value = newItem[attr.name] ?? '';
      set(initItem, attr.name, value);
    });
    return initItem;
  }

  async mounted() {
    if (this.value.__id) {
      this.items = Array.isArray(this.value.__id)
        ? this.value.__id
        : [this.value.__id];
    }

    if (this.includeColNames) {
      this.items.unshift(this.colNameItem);
    }

    this.$set(this, 'newItem', this.initItem(this.newItem));
  }

  deleteRow(deleteItem) {
    const deleteItemIdx = this.items.findIndex(
      (item) => item.rowId === deleteItem.row.rowId
    );
    if (deleteItemIdx !== -1) this.items.splice(deleteItemIdx, 1);
    this.deleteDialog = false;
    this.deleteItem = null;
    this.resetAttractions = true;
  }

  addRow(): void {
    const formGeneratorWrapper$ = this.$refs.formGeneratorWrapper;
    const formGenerator$ = formGeneratorWrapper$?.$refs
      ?.formGenerator as FormGenerator;

    if (!this.isValid) {
      formGenerator$ && formGenerator$.validate();

      return;
    }

    if (!this.selectedItem) {
      const newItem = { rowId: v4() };

      if (this.subSchema.attrList.some((attr) => attr.name === '__num')) {
        const num = this.includeColNames
          ? this.items.length
          : this.items.length + 1;

        newItem.__num = num;
      }

      //Корректное отображение словаря выводимого через MappedDictionary в TableFillView.
      Object.entries(this.newItem).forEach((item) => {
        const key = item[0];
        const content = item[1]?.content;
        const code = item[1]?.code;
        if (key === 'incomeType') {
          newItem[key] = {
            content,
            code,
          };
        } else if (content) {
          newItem[key] = content;
        } else {
          newItem[key] = item[1];
        }
      });

      this.items.push(newItem);

      // Object.keys(this.newItem).forEach((key) => delete this.newItem[key]);
      this.newItem = this.initItem();
    } else {
      const savedItem = { ...this.selectedItem };
      const savedItemIndex = this.items.findIndex(
        (item) => item.rowId === savedItem.rowId
      );
      if (savedItemIndex !== -1) {
        this.$set(this.items, savedItemIndex, savedItem);
        this.selectedItem = null;
      }
    }

    this.resetAttractions = true;
    formGenerator$.$forceUpdate();
    formGenerator$.$v.$reset();
  }

  toggleSelectItem(props): void {
    if (this.selectedItem?.rowId === props?.row?.rowId) {
      this.selectedItem = null;
    } else {
      this.selectedItem = { ...props.row };
    }

    this.resetAttractions = true;
  }

  generateEmptyEntry(): Model.Base {
    if (!this.attrs) return {} as Model.Base;

    return this.attrs.reduce((empty, nextAttr) => {
      empty[nextAttr.name] = void 0;

      return empty;
    }, {} as Model.Base);
  }

  updateValidation(isValid: boolean): void {
    this.formGeneratorIsValid = isValid;
  }

  displayValue(value: unknown): string {
    if (typeof value === 'boolean') {
      return value ? this.$t('base.yes') : this.$t('base.no');
    }

    return value;
  }
}
