<template>
  <div v-show="show" class="search-list">
    <avue-form
      ref="searchForm"
      v-if="isSetData"
      v-model="formObj"
      v-on="$listeners"
      :option.sync="finalOption"
    >
      <template slot="menuForm">
        <div class="search-button-container">
          <el-button size="small" @click="handleSearchReset"> {{ labels.reset }}</el-button>
          <el-button type="primary" size="small" @click="handleSearch">{{
            labels.search
          }}</el-button>
          <el-button size="small" type="text" @click="handleSearchHide">{{
            labels.close
          }}</el-button>
        </div>
      </template>
      <!-- 自定义slot -->
      <template v-for="item in customSlots" :slot="item.prop">
        <slot :name="item.slotName" />
      </template>
      <template v-for="item in itemLinkList" :slot="item.prop">
        <!-- <span :key="item.prop" v-if="excludeSlots[item.prop]">{{ item.prop }}</span> -->
        <component
          :is="item.component"
          :key="item.prop"
          :api="listApi[item.prop]"
          :list-params="listParams[item.prop]"
          :selected.sync="formObj[item.prop]"
          @selectDone="doSelect(item.func, formObj, $event, item.option || item.params)"
        />
      </template>
    </avue-form>
  </div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep';

import { STATION } from '../../../lib/const.js';
import { ft, getBusinessAccount, getObjType, getPropertiesInitValue } from '../../../lib/utils.js';
import { checkDataType } from '../core/utils.js';
import { getUserInfo } from '../../../lib/auth';

import popList from '../../../lib/popList';
import { LayoutConfigService } from '../../../lib/api/layoutConfig';
import { ElsPageConfigService } from '../../../lib/api/materials';
import { i18nConfig } from '../../../mixins/i18n';

const LABELS = {
  close: ft('i18n_common_close', '关闭'),
  from: ft('i18n_common_from', '从'),
  listConfiguration: ft('i18n_common_list_configuration', '列表配置'),
  reset: ft('i18n_common_reset', '重置'),
  search: ft('i18n_common_search', '搜索'),
  searchListConfiguration: ft('i18n_common_search_list_configuration', '搜索列表配置'),
  to: ft('i18n_common_to', '到')
};

export default {
  name: 'SearchProvider',
  mixins: [i18nConfig],
  props: {
    // customSlots: 自定义 slots, 只输出 slot name, 具体内容由使用者定义(不在组件内部定义)
    customSlots: {
      type: Array,
      default: function () {
        return [];
      }
    },
    // 表单元素默认 span, 默认值为 6
    defaultElementSpan: {
      type: Number,
      default: 6
    },

    // excludeSlots, 当 按popup 方式展现搜索条件中预置的 popup 表单时, 排除指定的表单
    excludeSlots: {
      type: Object,
      default: function () {
        return {};
      }
    },

    extendDic: {
      type: Array,
      default: function () {
        return [];
      }
    },

    /**
     * @property {Function} handleMetadataBeforeFn - 设置查询属性定义之前修改元数据
     */
    handleMetadataBeforeFn: {
      type: Function,
      default: null
    },

    // itemLinkList: 预置的 支持 popup 方式展现的表单列表
    itemLinkList: {
      type: Array,
      default: function () {
        return cloneDeep(popList);
      }
    },

    listApi: {
      type: Object,
      default: function () {
        return {};
      }
    },

    listParams: {
      type: Object,
      default: function () {
        return {};
      }
    },

    // pageCode: 配置平台的列表页面的配置编码
    pageCode: {
      type: String,
      default: ''
    },

    // searchColumns: 直接输入查询字段的定义
    searchColumns: {
      type: Array,
      default: function () {
        return [];
      }
    },

    // searchPageCode: 配置平台的列表页面的搜索字段的配置编码, 与原有管理列表列字段设置数据相同(订单, 招标)
    searchPageCode: {
      type: String,
      default: ''
    },

    /**
     * @property {Function} setExcludeSlotsFn - 设置排除自定义字段方法
     */
    setExcludeSlotsFn: {
      type: Function,
      default: null
    },

    /**
     * @property {Function} setSearchColumnFn - 修改查询属性
     * @see setSearchColumn
     */
    setSearchColumnFn: {
      type: Function,
      default: null
    },

    // show: 是否显示搜索条件的表单区域
    show: {
      type: Boolean,
      default: false
    },

    // showPreSlots: 是否 以 popup 方式展现搜索条件中预置的 popup 表单, 默认 false 按文本输入框方式展现
    showPreSlots: {
      type: Boolean,
      default: false
    },

    // supportTimePeriodQuery: 是否支持时间段查询, 适用于日期或时间类型的字段
    supportTimePeriodQuery: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      labels: LABELS,
      finalOption: {
        menuBtn: true,
        emptyBtn: false,
        clearBtn: false,
        submitBtn: false,
        column: []
      },
      isSetData: false,
      delayFormData: null,
      formObj: {},
      reload: false,
      formSlots: [],
      optionHash: '',
      typeData: [],
      selected: {},
      configurations: {},
      uploadField: ''
    };
  },

  computed: {
    businessElsAccount() {
      const userInfo = getUserInfo();
      // 获取用于查询配置信息的供应商对应的 businessElsAccount
      return userInfo.station === STATION.SALE ? getBusinessAccount(userInfo) : '';
    }
  },

  watch: {
    // 暂时无需监测
    formObj: {
      handler: function (newVal, oldVar) {
        this.$emit('on-update', newVal);
        this.$emit('update:data', newVal);
      },
      immediate: true,
      deep: true
    },
    show(newVal) {
      this.finalOption.menuBtn = newVal;
    }
  },
  async created() {
    this.loadConfigurations();
  },
  methods: {
    checkSlot(item) {
      const itemLinkList = this.itemLinkList;

      for (const linkItem of itemLinkList) {
        // 非只读元素 可以弹窗
        if (
          item.prop === linkItem.prop &&
          !this.excludeSlots[item.prop] &&
          item.isReadOnly !== 'Y'
        ) {
          item.formslot = true;
          item.slot = true;
          break;
        }
      }
    },

    doSelect(func, row, event, params = []) {
      const type = getObjType(this[func]);

      if (type === 'function') {
        this[func](row, event, params);
      }

      const field = params[0] || 'materialNumber';

      this.$emit('on-select', field, row);

      this.$forceUpdate();
    },

    async filterColum(columns = [], option = {}) {
      const customSlotPropItems = {};
      const customSlots = this.customSlots || [];
      customSlots.forEach((item) => {
        if (item.prop) {
          customSlotPropItems[item.prop] = 1;
        }
      });
      for (const item of columns) {
        delete item.readonly;

        if (item.displayName) {
          item.label = item.displayName;
        }

        if (customSlotPropItems[item.prop] && item.formslot !== true) {
          item.formslot = true;
        }

        this.setI18n(item);

        await checkDataType(item);

        if (this.showPreSlots === true || this.showPreSlots === 'true') {
          if (this.excludeSlots[item.prop]) {
            this.removePreSlot(item.prop);

            item.type = 'input';

            delete item.formslot;
            delete item.slot;
          }

          // 检查是否 slot 元素
          this.checkSlot(item);
        } else {
          if (item.datatype === 'popup') {
            item.type = 'input';
            delete item.formslot;
            delete item.slot;
          }
        }

        if (option.isSearchColumn === true) {
          delete item.disabled;
        }

        item.display = true;
        item.span = item.span || this.defaultElementSpan;
      }

      return columns;
    },

    async filterTableColum(refCrudName = '', columns) {
      const waitUpdateDic = [];

      for (const item of columns) {
        await checkDataType(item);

        if (item.displayName) {
          item.label = item.displayName;
        }

        item.display = true;
      }

      if (!refCrudName) {
        const crud = this.$refs[refCrudName];

        waitUpdateDic.map((prop) => {
          if (crud && prop) {
            crud.updateDic(prop);
          }
        });
      }

      return columns;
    },

    getData() {
      return this.formObj;
    },

    handleConfigData(results) {
      const pageConfiguration = results[0];
      const searchConfiguration = results[1];

      const inputSearchColumns = this.searchColumns.length > 0 ? this.searchColumns : null;

      const searchItems =
        inputSearchColumns || searchConfiguration || pageConfiguration.search || [];

      if (typeof this.handleMetadataBeforeFn === 'function') {
        this.handleMetadataBeforeFn(searchItems);
      }

      const searchColumns = [];

      searchItems.map((item) => {
        if (
          this.supportTimePeriodQuery === true &&
          (item.datatype === 'datetime' || item.datatype === 'date')
        ) {
          const { from, to } = this.setQueryDateColumn(item);

          searchColumns.push(from);
          searchColumns.push(to);
        } else {
          searchColumns.push(item);
        }
      });

      this.finalOption.column = searchColumns;

      this.updateColumn({});

      // 有 pageCode 时，更新 列表字段
      if (pageConfiguration.list) {
        const listColumn = this.preHandList(pageConfiguration.list);
        this.setTableColumns(listColumn, pageConfiguration);
      }
    },

    handleSearch() {
      const formObj = {};

      Object.keys(this.formObj).map((key) => {
        if (this.formObj[key] !== '') {
          formObj[key] = this.formObj[key];
        }
      });

      const formData = cloneDeep(formObj);

      for (const key in formData) {
        if (key.indexOf('$') === 0) {
          delete formData[key];
        }
      }

      this.$emit('do-search', formData);
    },

    handleSearchHide() {
      this.show = false;
      this.$emit('do-hide');
    },

    handleSearchReset() {
      this.$refs.searchForm.resetForm();

      this.$emit('do-reset');
    },

    loadConfigurations() {
      Promise.all([this.loadPageConfiguration(), this.loadSearchConfiguration()]).then(
        (results) => {
          this.handleConfigData(results);
        }
      );
    },

    loadPageConfiguration() {
      return new Promise((resolve, reject) => {
        if (this.pageCode) {
          const resData = this.businessElsAccount
            ? {
                elsAccount: this.businessElsAccount,
                code: this.pageCode
              }
            : {
                code: this.pageCode
              };

          ElsPageConfigService.list(resData)
            .then((res) => {
              if (res.data && res.data.statusCode === '200' && res.data.data) {
                try {
                  const data = res.data.data;
                  const configJson = data.outputJson || '{}';
                  const json = JSON.parse(configJson);

                  resolve(json);
                } catch (err) {
                  console.log('Failed to convert list configuration to JSON.');
                  reject(err);
                }
              } else {
                console.log('Failed to load list configuration, ', res.data);
                this.$message.error(
                  res.data.message ||
                    LABELS.failedToQueryData.replace('?', LABELS.listConfiguration)
                );
                reject(new Error('Failed to load list configuration.'));
              }
            })
            .catch((err) => {
              console.log('Error to load list configuration, ', err);
              this.$message.error(LABELS.failedToQueryData.replace('?', LABELS.listConfiguration));
              reject(err);
            });
        } else {
          resolve({});
        }
      });
    },

    loadSearchConfiguration() {
      return new Promise((resolve, reject) => {
        if (this.searchPageCode) {
          const resData = this.businessElsAccount
            ? {
                elsAccount: this.businessElsAccount,
                code: this.searchPageCode
              }
            : {
                code: this.searchPageCode
              };

          LayoutConfigService.listConfigByCode(resData)

            .then((res) => {
              if (res.data && res.data.code === '200' && res.data.data) {
                try {
                  const firstItem = res.data.data[0] || {};
                  const configJson = firstItem.configJson || '{}';
                  const list = JSON.parse(configJson);
                  const searchColumns = list.filter((item) => item.isSearch === 'Y');

                  for (const searchColumn of searchColumns) {
                    searchColumn.sequence = searchColumn.$index;
                    delete searchColumn.$index;
                    delete searchColumn.$type;
                    delete searchColumn.order;
                    delete searchColumn.slot;
                  }

                  const linkItems = list.filter((item) => item.type === 'link');

                  for (const linkItem of linkItems) {
                    linkItem.type = 'input';
                  }

                  // searchColumns.sort(sort);

                  // // eslint-disable-next-line no-inner-declarations
                  // function sort(a, b) {
                  //   return a.sequence - b.sequence;
                  // }

                  resolve(searchColumns);
                } catch (err) {
                  console.log('Failed to convert search list configuration to JSON.', err);
                  resolve(null);
                }
              } else {
                console.log('Failed to load search list configuration, ', res.data || res);
                this.$message.error(
                  res.data.message ||
                    LABELS.failedToQueryData.replace('?', LABELS.searchListConfiguration)
                );
                resolve(null);
              }
            })
            .catch((err) => {
              console.log('Error to load search list configuration, ', err);
              LABELS.failedToQueryData.replace('?', LABELS.searchListConfiguration);
              resolve(null);
            });
        } else {
          resolve(null);
        }
      });
    },

    removePreSlot(prop) {
      let index = 0;
      let propIndex = -1;

      for (const item of this.itemLinkList) {
        const params = item.params || [];

        if (item.prop === prop || params.indexOf(prop) > -1) {
          propIndex = index;

          break;
        }

        index = index + 1;
      }

      if (propIndex > -1) {
        this.itemLinkList.splice(propIndex, 1);
      }
    },

    replaceWithExtendDic(item) {
      const extendList = this.extendDic;

      if (extendList.length) {
        extendList.map((extendItem) => {
          if (item.prop === extendItem.prop) {
            Object.assign(item, extendItem);
            delete item.dicUrl;
            delete item.bizDic;
            delete item.datatype;
          }
        });
      }
    },

    preHandList(list) {
      const newList = list || [];

      newList.map((item) => {
        if (item.displayName) {
          item.label = item.displayName;
        }
      });

      return newList;
    },

    saveSelected(row, list, option) {
      const item = list[0];
      const matchProps = this.propMatch;

      let ref = '';

      if (option.isOption === true) {
        ref = option.valueProp;

        const dataValue = item[option.dataValueProp];
        const dataName = item[option.dataNameProp];

        if (typeof dataValue !== 'undefined' && typeof row[option.valueProp] !== 'undefined') {
          row[option.valueProp] = dataValue;
        }

        if (typeof dataName !== 'undefined') {
          const nameProp = option.nameProp;

          if (nameProp && typeof row[nameProp] !== 'undefined') {
            row[nameProp] = dataName;
          } else {
            const aliasProps = option.aliasProps || [];
            for (const aliasProp of aliasProps) {
              if (typeof row[aliasProp] !== 'undefined') {
                row[aliasProp] = dataName;
                break;
              }
            }
          }
        }
      } else {
        const params = option;
        ref = params[0];

        // value 赋值
        if (params[0] && params[2]) {
          row[params[0]] = item[params[2]];
        }

        // 名字 赋值
        if (params[1] && params[3]) {
          row[params[1]] = item[params[3]];
        }

        // 别名 赋值
        if (params[4] && params[3]) {
          row[params[4]] = item[params[3]];
        }
      }

      if (matchProps && matchProps.length) {
        matchProps.map((matchItem) => {
          if (matchItem.ref === ref) {
            row[matchItem.to] = item[matchItem.from];
          }
        });
      }
    },

    setDelayFormData() {
      if (this.delayFormData) {
        this.setFormData(this.delayFormData);
      }
    },

    /**
     * 在外部引用组件更新表单数据
     */
    setFormData(data) {
      if (this.isSetData) {
        this.formObj = data;
        this.delayFormData = null;
      } else {
        this.delayFormData = data;
      }
    },

    setHeadColumns(businessTypeValue, option = null) {
      const selected = this.configurations[businessTypeValue];

      if (selected) {
        this.selected = selected;
        this.updateColumn(businessTypeValue, selected, option);
      }
    },

    setQueryDateColumn(item) {
      const from = cloneDeep(item);
      const to = cloneDeep(item);

      from.prop = from.prop + 'From';
      from.label = from.label + ' ' + LABELS.from; // ' from'

      to.prop = to.prop + 'To';
      to.label = to.label + ' ' + LABELS.to; // ' to'

      return {
        from,
        to
      };
    },

    /**
     * 在外部引用组件更新表单属性
     */
    setSearchColumn() {
      if (typeof this.setSearchColumnFn === 'function') {
        this.setSearchColumnFn(this.finalOption.column);
      }
    },

    setTableColumns(list, json) {
      this.$emit('updateTableColumn', list, json);
    },

    async updateColumn() {
      const columns = this.finalOption.column;

      if (typeof this.setExcludeSlotsFn === 'function') {
        this.setExcludeSlotsFn(this.itemLinkList, columns);
      }

      const newColumns = await this.filterColum(JSON.parse(JSON.stringify(columns)), {
        isSearchColumn: true
      });

      this.finalOption.column = [];
      const optionColumns = this.finalOption.column;

      const waitUpdateDic = [];
      newColumns.map((item) => {
        this.replaceWithExtendDic(item);

        optionColumns.push(item);

        if (item.dicUrl) {
          waitUpdateDic.push(item.prop);
        }
      });

      this.updateDic(waitUpdateDic);

      const formEmptyValue = getPropertiesInitValue(optionColumns, 'prop', '');

      this.formObj = formEmptyValue;

      this.isSetData = true;

      this.setDelayFormData();
    },

    updateDic(list) {
      const form = this.$refs.searchForm;
      if (form) {
        list.map((prop) => {
          form.updateDic(prop);
        });
      } else {
        setTimeout(() => {
          this.updateDic(list);
        }, 1000);
      }
    },

    updateListColumn(list) {
      list.map((item) => {
        this.replaceWithExtendDic(item);
      });
    },

    updateSearchParams(field, params) {
      // 更新 弹窗过滤条件
    }
  }
};
</script>
<style lang="scss">
@import './list.scss';
</style>
<style lang="scss" scoped>
.search-button-container {
  width: 100%;
  text-align: right;
}
</style>
