<template>
  <div class="head-list">
    <avue-form
      ref="form"
      v-if="setConfigFormState === CONFIG_FORM_STATE.READONLY"
      v-model="data"
      v-on="$listeners"
      :option.sync="finalOption"
    >
      <template v-for="item in itemLinkList" :slot="item.prop">
        <span v-if="data[item.prop]" :key="item.prop">
          {{ data[item.prop] }}
        </span>
      </template>
      <!-- 自定义slot -->
      <template v-for="item in customSlots" :slot="item.prop">
        <slot :slot-scope="row" :name="item.slotName" />
      </template>
    </avue-form>

    <avue-form
      ref="form"
      v-else-if="setConfigFormState === CONFIG_FORM_STATE.READY"
      v-model="formObj"
      v-on="$listeners"
      :option.sync="finalOption"
    >
      <!-- 自定义slot -->
      <template v-for="item in customSlots" :slot="item.prop" slot-scope="{ row }">
        <slot :slot-scope="row" :name="item.slotName" />
      </template>

      <template v-for="item in itemLinkList" :slot="item.prop">
        <span v-if="readOnly" :key="item.prop">
          {{ formObj[item.prop] }}
        </span>
        <component
          :is="item.component"
          v-else
          :key="item.prop"
          :selected.sync="formObj[item.prop]"
          :api="listApi[item.prop]"
          :list-params.sync="listParams[item.prop]"
          :is-disabled="getDisabledProperty(item.prop)"
          @selectDone="doSelect(item.func, formObj, $event, item.option || item.params, item)"
        />
      </template>
    </avue-form>
  </div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep';
import { checkDataType, checkFixDic, handlerSystemFiled, setRequired } from '../core/utils.js';
import {
  ft,
  generateDictURLWithLang,
  getBusinessAccount,
  getPropertiesInitValue,
  isDictURL
} from '../../../lib/utils.js';
import { i18nConfig } from '../../../mixins/i18n';
import popList from '../../../lib/popList';
import { ElsTemplateConfigService } from '../../../lib/api/materials';

const LABELS = {
  businessType: ft('i18n_common_business_type', '业务类型'),
  cancel: ft('i18n_common_cancel', '取消'),
  configuration: ft('i18n_common_configuration', '配置'),
  confirm: ft('i18n_common_confirm', '确定'),
  failedToQueryData: ft('i18n_common_failed_to_query_specified_data', '查询?数据失败'),
  uploading: ft('i18n_common_uploading', '上传中...')
};

const CONFIG_FORM_STATE = {
  WAIT: 0,
  READONLY: 1,
  READY: 2
};

export default {
  name: 'HeadProvider',
  mixins: [i18nConfig],
  props: {
    // elsAccountStation：远程获取 表格字段数据配置- 后续扩充 from 类型
    elsAccountStation: {
      type: String,
      default: ''
    },
    // businessModule: 远程获取 表格字段数据配置- 后续扩充 from 类型
    businessModule: {
      type: String,
      default: 'requisition'
    },
    // businessType： 远程获取 表格字段数据配置- 后续扩充 from 类型
    businessType: {
      type: String,
      default: ''
    },
    // businessTypeProperty: 用于匹配实际的业务类型数据属性
    businessTypeProperty: {
      type: String,
      default: function () {
        return '';
      }
    },
    // enAbleI18n: 是否支持多语言
    enAbleI18n: {
      type: Boolean,
      default: true
    },
    // businessTypeValue: 业务类型数据, 用于 hideTable == true 时, 表单显示内容的刷新
    businessTypeValue: {
      type: String,
      default: ''
    },
    // businessTypeVersion: 业务类型版本
    businessTypeVersion: {
      type: String,
      default: ''
    },
    col: {
      type: Number,
      default: 0
    },
    data: {
      type: Object,
      default: function () {
        return {};
      }
    },
    // hideTable: 是否禁止 下面的表格，选择 true 时, 不显示 下面的表格, 只显示上面的表单
    // 通常用于只需要填写或显示表单的场景
    hideTable: {
      type: Boolean,
      default: false
    },
    // customSlots: 自定义 slots, 只输出 slot name, 具体内容由使用者定义(不在组件内部定义)
    customSlots: {
      type: Array,
      default: function () {
        return [];
      }
    },
    // excludePreSlots: 排除组件内置的预定义的字段(属性)Slot, 例如 :excludePreSlots=['materialNumber']
    excludePreSlots: {
      type: Array,
      default: function () {
        return [];
      }
    },
    // itemLinkList: 组件内置的预定义的字段(属性)Slot
    itemLinkList: {
      type: Array,
      default: function () {
        return cloneDeep(popList);
      }
    },
    listApi: {
      type: Object,
      default: function () {
        return {};
      }
    },
    listParams: {
      type: Object,
      default: function () {
        return {};
      }
    },

    /**
     * @property {Function} handleMetadataFn - 设置表单元数据属性的方法
     */
    handleMetadataFn: {
      type: Function,
      default: null
    },

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

    option: {
      type: Object,
      default: function () {
        return { column: [] };
      }
    },
    originColumn: {
      type: Array,
      default: function () {
        return [];
      }
    },

    // readOnly: 是否只读模式
    readOnly: {
      type: Boolean,
      default: false
    },

    rowPermission: {
      type: Object,
      default: function () {
        return {};
      }
    },
    // status: 远程获取 表格字段数据配置- 后续扩充 from 类型
    status: {
      type: String,
      default: 'new'
    },

    /**
     * @property {Object[Function]} columnDefineProcFns - 列属性规则处理方法集合
     */
    columnDefineProcFns: {
      type: Object,
      default: null
    }
  },
  data() {
    return {
      CONFIG_FORM_STATE: CONFIG_FORM_STATE,
      setConfigFormState: CONFIG_FORM_STATE.WAIT,

      disabledProperties: {},
      loadingConfig: false,
      isChanged: false,

      finalOption: {
        menuBtn: false,
        submitBtn: false,
        clearBtn: false,
        column: [
          {
            label: LABELS.businessType,
            prop: 'businessType',
            type: 'select',
            span: 8,
            disabled: true
          }
        ]
      },
      defaultValues: {},
      formObj: {},

      reload: false,
      formSlots: [],
      optionHash: '',

      configurations: {},

      selected: {},
      typeDicts: [],
      typeData: {},
      res: []
    };
  },
  watch: {
    'formObj.businessType'(newVal, oldVal) {
      if (newVal && oldVal && newVal !== oldVal) {
        this.setHeadColumns(newVal, {
          isChanged: true
        });

        this.setTableColumns(newVal);

        this.$emit('businessTypeChange', newVal);
      }
    },

    businessTypeValue(newVal) {
      if (newVal && newVal !== '') {
        this.setHeadColumns(newVal, {
          isChanged: true
        });
        /* 用于刷新表单, 因此不操作下面的表格, 具体参考属性说明
         this.setTableColumns(newVal);
        */
      }
    },
    data: {
      handler: function (newVal, oldVar) {
        // 父对象更新 同步到 绑定对象
        this.formObj = newVal;
      },
      immediate: true, // 刷新加载 立马触发一次 handler
      deep: true // 可以深度检测到 对象的属性值的变化
    },
    formObj(newVal) {
      if (!this.readOnly) {
        // 更新内容 同步更新到父对象
        this.$emit('update:data', newVal);
      }
    }
  },
  async created() {
    this.initOption();
    this.loadConfigurations();
  },
  methods: {
    checkForm(callback, failback) {
      this.$refs.form.validate((valid, done) => {
        if (valid) {
          callback && callback(done);
        } else {
          failback && failback();
          return false;
        }
      });
    },

    doSelect(func, row, event, params = [], column) {
      this.$emit('select-done', { row, event, params, column });
      this[func](row, event, params);
      this.$forceUpdate();
    },

    async filterColum(columns) {
      const customSlotPropItems = {};

      const customSlots = this.customSlots || [];

      customSlots.forEach((item) => {
        if (item.prop) {
          customSlotPropItems[item.prop] = 1;
        }
      });

      for (const item of columns) {
        const selected = this.selected;
        const itemProp = selected.fieldPermission[item.prop];

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

        await checkDataType(item);
        checkFixDic(item, this.fixSeleteDic);

        item.hide = true;
        item.display = false;

        if (itemProp) {
          if (itemProp.display && itemProp.display !== false) {
            if (typeof itemProp.value !== 'undefined') {
              this.defaultValues[item.prop] = itemProp.value;
              delete itemProp.value;
              delete item.value;
            } else if (item.type === 'radio' && item.dicData && item.dicData.length > 0) {
              if (item.dicData[0] && typeof item.dicData[0].value !== 'undefined') {
                this.defaultValues[item.prop] = item.dicData[0].value;
              }
            }

            // 如果配置了国际化标签并启用了国际化
            if (this.enAbleI18n) {
              this.setI18n(item);
            } else {
              this.setDisplayName(item);
            }

            // 如果有默认值 进行赋值处理
            if (itemProp.value) {
              item.value = itemProp.value;
            }

            if (itemProp.isRequired === 'Y') {
              itemProp.isRequired = true;
            } else if (itemProp.isRequired === 'N') {
              itemProp.isRequired = false;
            }

            const isRequired = !!itemProp.isRequired;

            if (isRequired) {
              setRequired(item);
            }

            if (item.prop.includes('Document') || item.datatype === 'uploadFile') {
              item.formslot = true;
            }

            // 检查特定字段 固定处理
            if (itemProp.isDisabled || itemProp.isSystem === 'Y') {
              item.disabled = 'disabled';
              item.cell = false;
              item.rules = [];
            } else {
              item.cell = true;
            }

            if (item.isDisabled) {
              item.disabled = 'disabled';
            }

            if (item.isDisabled || itemProp.isDisabled || itemProp.isReadOnly === 'Y') {
              this.disabledProperties[item.prop] = 1;
            }

            if (item.isSystem === 'Y' || item.isReadOnly === 'Y') {
              handlerSystemFiled(item);
            }

            item.display = true;
            item.span = item.span || 6;

            if (item.prop === 'requireContent') {
              item.formslot = true;
              item.span = 24;
              item.order = -1;
              item.type = 'text';
            }

            if (
              this.columnDefineProcFns &&
              typeof this.columnDefineProcFns[item.prop] === 'function'
            ) {
              this.columnDefineProcFns[item.prop].call(this, item);
            }
          }
        } else {
          if (item.isSystem === 'Y') {
            item.disabled = 'disabled';
            item.rule = [];
          }
        }
      }

      return columns;
    },

    filterPreSlots() {
      if (this.excludePreSlots.length > 0) {
        const preSlots = this.itemLinkList.filter((item) => {
          return !this.excludePreSlots.includes(item.prop);
        });

        this.itemLinkList = preSlots;
      }
    },

    getData() {
      const formData = JSON.parse(JSON.stringify(this.formObj));

      // 输出 templateName, templateVersion 供用户使用, 可能需要在接受后再处理为业务需要的值或抛弃(删除)
      if (formData.businessType && this.typeData[formData.businessType]) {
        const businessTypeData = this.typeData[formData.businessType];
        formData.businessTypeName = businessTypeData.templateName;
        formData.businessTypeVersion = businessTypeData.templateVersion;
      }

      // set real business type data and remove virtual business type data
      if (this.businessTypeProperty) {
        formData[this.businessTypeProperty] = formData.businessType;
      }

      delete formData.businessType;

      return formData;
    },

    getDisabledProperty(prop) {
      return this.disabledProperties[prop] || false;
    },

    go(item, row) {
      if (window.parent) {
        const router = {
          name: item.label,
          src: item.url + row[item.prop]
        };

        const event = {
          name: 'openNewTag',
          props: router
        };

        window.parent.postMessage(event, '*');
      } else {
        window.location.href = item.url;
      }
    },

    initConfigItem(item, option = null) {
      const configJson = item.configJson || '{}';
      const json = JSON.parse(configJson);
      const fields = json.field || [];
      const fieldJson = json.fieldJson || {};
      const userStation = this.elsAccountStation || '';

      const table = json.table || [];
      const tableJson = json.tableJson || {};

      // 排除非法数据 $index
      for (const field of fields) {
        delete field.$index;
      }

      for (const tbl of table) {
        delete tbl.$index;
      }

      const fieldPermission = fieldJson[userStation] || {};
      const tablePermission = tableJson[userStation] || {};
      const saleTablePermission = tableJson.sale || {};

      // 由于与 businessType 重复, 如存在则删除 businessTypeProperty 对应的属性
      let fieldIndex = 0;

      for (const fieldItem of fields) {
        if (fieldItem.prop === this.businessTypeProperty) {
          fields.splice(fieldIndex, 1);
          break;
        }

        fieldIndex = fieldIndex + 1;
      }

      this.configurations[item.templateNumber] = {
        name: item.templateName,
        fieldColumns: fields,
        fieldPermission: fieldPermission,
        rule: json.rule || {},
        saleTablePermission: saleTablePermission,
        tableColumns: table,
        tablePermission: tablePermission
      };

      if (!this.formObj.businessType) {
        this.formObj.businessType = item.templateNumber;
      }

      option
        ? this.setHeadColumns(item.templateNumber, {
            ...option,
            fieldPermission
          })
        : this.setHeadColumns(item.templateNumber, {
            fieldPermission
          });

      this.setTableColumns(item.templateNumber);
    },

    initData() {
      const defaultValueKeys = Object.keys(this.defaultValues);

      if (!this.readOnly && defaultValueKeys.length > 0) {
        const formKeys = Object.keys(this.formObj);
        const keySet = new Set([...formKeys, ...defaultValueKeys]);

        const mergedObject = {};

        for (const key of keySet.keys()) {
          mergedObject[key] = this.formObj[key] || this.defaultValues[key];
        }

        this.formObj = mergedObject;
      }
    },

    initOption() {
      if (this.readOnly) {
        this.finalOption.detail = true;
      } else {
        this.finalOption.detail = false;
      }
    },

    loadConfigurationItem(param, option = null) {
      if (param) {
        ElsTemplateConfigService.detail(param)

          .then((res) => {
            if (res.data && res.data.code === '200' && res.data.data && res.data.data.configJson) {
              option
                ? this.initConfigItem(res.data.data, option)
                : this.initConfigItem(res.data.data);
            } else {
              const resData = res.data || res;
              console.log('Failed to detail ticket business type configurations.', res.data);
              this.$message.error(
                resData.message ||
                  LABELS.failedToQueryData.replace(
                    '?',
                    `${LABELS.businessType.toLowerCase()} ${LABELS.configuration.toLowerCase()}`
                  )
              );
            }
          })
          .catch((err) => {
            this.typeDicts = [];

            console.log('Error to detail ticket business type configurations.', err);
            this.$message.error(
              LABELS.failedToQueryData.replace(
                '?',
                `${LABELS.businessType.toLowerCase()} ${LABELS.configuration.toLowerCase()}`
              )
            );
          });
      }
    },

    loadConfigurations() {
      if (this.loadingConfig) {
        return;
      }

      this.loadingConfig = true;

      // 查看状态下，不再查询配置列表, 直接查询具体的配置数据
      if (
        this.businessTypeValue &&
        this.businessTypeVersion &&
        (this.readOnly === true || this.readOnly === 'true')
      ) {
        const param = {
          templateNumer: this.businessTypeValue,
          templateVersion: this.businessTypeVersion
        };

        return this.loadConfigurationItem(param, {
          isInitial: true
        });
      }

      ElsTemplateConfigService.list({
        elsAccount: getBusinessAccount(),
        businessModule: this.businessModule,
        currentVersionFlag: 'Y'
      })
        .then((res) => {
          const TypeDicts = [];

          if (res.data && res.data.code === '200' && res.data.data) {
            const rows = res.data.data.rows || [];
            this.res = rows;

            if (rows.length < 1) {
              return;
            }

            this.setConfigurations(rows);
          } else {
            this.typeDicts = TypeDicts;

            const resData = res.data || res;
            console.log('Failed to list ticket business type configurations.', res.data);
            this.$message.error(
              resData.message ||
                LABELS.failedToQueryData.replace(
                  '?',
                  `${LABELS.businessType.toLowerCase()} ${LABELS.configuration.toLowerCase()}`
                )
            );
          }
        })
        .catch((err) => {
          this.typeDicts = [];
          console.log('Error to list ticket business type configurations.', err);
          this.$message.error(
            LABELS.failedToQueryData.replace(
              '?',
              `${LABELS.businessType.toLowerCase()} ${LABELS.configuration.toLowerCase()}`
            )
          );
        });
    },

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

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

      let ref = '';

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

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

        if (option.valueProp) {
          row[option.valueProp] = '';
        }

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

        if (typeof dataName !== 'undefined') {
          const nameProp = option.nameProp;
          if (nameProp) {
            row[nameProp] = '';
          }
          if (nameProp && typeof row[nameProp] !== 'undefined') {
            row[nameProp] = dataName;
          }
          const aliasProps = option.aliasProps || [];
          for (const aliasProp of aliasProps) {
            if (aliasProp) {
              row[aliasProp] = '';
            }
            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 (matchProp && matchProp.length) {
        matchProp.map((matchItem) => {
          if (matchItem.ref === ref) {
            row[matchItem.to] = item[matchItem.from];
          }
        });
      }
      // 手动触发验证
      if (ref && this.$refs.form) {
        this.$refs.form.validateField(ref);
      }
    },

    setConfigurations(rows) {
      const TypeDicts = [];

      const defaultNumber =
        this.data.businessType || this.data[this.businessTypeProperty] || rows[0].templateNumber;

      const TypeData = {};

      for (const item of rows) {
        TypeData[item.templateNumber] = {
          templateName: item.templateName,
          templateNumer: item.templateNumber,
          templateVersion: item.templateVersion,
          id: item.uuid
        };

        TypeDicts.push({
          value: item.templateNumber,
          label: item.templateName
        });
      }

      this.typeData = TypeData;
      this.typeDicts = TypeDicts;

      this.setHeadColumns(defaultNumber, {
        isChanged: false
      });

      const form = this.$refs.form;

      if (form && form.updateDic) {
        form.updateDic('businessType', this.typeDicts);
      }
    },

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

      // 加载模版
      if (selected) {
        this.selected = selected;
        this.updateColumn(businessTypeValue, selected, option);
      } else {
        const param = this.typeData[businessTypeValue];
        this.loadConfigurationItem(param);
      }
    },

    setTableColumns(val) {
      if (!this.hideTable) {
        const selected = this.configurations[val];

        if (selected) {
          this.$emit('updateType', selected);
        } else {
          console.log('configurations not exists: ', val);
        }
      }
    },

    async updateColumn(businessTypeValue, selected, option = {}) {
      this.setConfigFormState = CONFIG_FORM_STATE.WAIT;

      const isChanged = option.isChanged;
      const isInitial = option.isInitial;
      const fieldPermission = option.fieldPermission || null;

      const columns = this.finalOption.column;

      columns.length = 1;

      if (isInitial === true) {
        columns[0].dicData = [
          {
            label: selected.name,
            value: businessTypeValue
          }
        ];
      }

      if (typeof this.handleMetadataBeforeFn === 'function') {
        this.handleMetadataBeforeFn(selected.fieldColumns, {
          fieldPermission
        });
      }

      this.filterPreSlots();

      const newColumn = await this.filterColum(selected.fieldColumns);

      const waitUpdateDic = [];

      newColumn.map((item) => {
        // 统一 一行三个
        item.span = item.span || 8;
        columns.push(item);

        if (item.dicUrl) {
          if (isDictURL(item.dicUrl)) {
            item.dicUrl = generateDictURLWithLang(item.dicUrl, true);
          }
          waitUpdateDic.push(item.prop);
        }
      });

      if (isChanged === true) {
        const formEmptyValue = getPropertiesInitValue(columns, 'prop', '');
        formEmptyValue.businessType = businessTypeValue;
        this.formObj = formEmptyValue;
      }

      if (typeof this.handleMetadataFn === 'function') {
        this.handleMetadataFn(this.finalOption.column);
      }

      this.initData();

      this.$nextTick(() => {
        this.setConfigFormState = this.readOnly
          ? CONFIG_FORM_STATE.READONLY
          : CONFIG_FORM_STATE.READY;

        this.$nextTick(() => {
          this.updateFormDict(waitUpdateDic);
        });
      });
    },

    updateFormDict(dicts) {
      const form = this.$refs.form;

      if (form && form.updateDic) {
        form.updateDic('businessType', this.typeDicts);
      }

      if (form && form.updateDic) {
        dicts.map((prop) => {
          form.updateDic(prop);
        });
      }
    }
  }
};
</script>
<style lang="scss">
@import './list.scss';
</style>
