<template>
  <div class="head-list">
    <avue-form
      ref="form"
      v-if="isSetConfigForm && readOnly"
      v-model="data"
      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="data[item.prop]" :key="item.prop">
          {{ data[item.prop] }}
        </span>
      </template>
    </avue-form>
    <avue-form
      ref="form"
      v-else-if="isSetConfigForm"
      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]"
          :listParams.sync="listParams[item.prop]"
          :is-disabled="getDisabledProperty(item.prop)"
          @selectDone="doSelect(item.func, formObj, $event, item.option || item.params)"
        />
      </template>
    </avue-form>
  </div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep';
import { checkDataType, checkFixDic, handlerSystemFiled, setRequired } from '../core/utils.js';
import { generateDictURLWithLang, getPropertiesInitValue, isDictURL } from '../../../lib/utils.js';
import popList from '../../../lib/popList';
import { i18nConfig } from '../../../mixins/i18n';

export default {
  name: 'BusinessFormsProvider',
  mixins: [i18nConfig],
  props: {
    // customSlots: 自定义 slots, 只输出 slot name, 具体内容由使用都定义(不在组件内部定义)
    customSlots: {
      type: Array,
      default: function () {
        return [];
      }
    },
    col: {
      type: Number,
      default: 0
    },
    data: {
      type: Object,
      default: function () {
        return {};
      }
    },
    // configOption: 外部提供数据来源, 通过 sessionStorage 加载数据 { name: string, timestamp: timestamp }
    configOption: {
      type: Object,
      default: function () {
        return null;
      }
    },
    itemLinkList: {
      type: Array,
      default: function () {
        return cloneDeep(popList);
      }
    },
    listApi: {
      type: Object,
      default: function () {
        return {};
      }
    },
    listParams: {
      type: Object,
      default: function () {
        return {};
      }
    },
    option: {
      type: Object,
      default: function () {
        return { column: [] };
      }
    },
    originColumn: {
      type: Array,
      default: function () {
        return [];
      }
    },
    // readOnly: 是否只读模式
    readOnly: {
      type: Boolean,
      default: false
    },
    // enAbleI18n: 是否支持多语言
    enAbleI18n: {
      type: Boolean,
      default: true
    },
    rowPermission: {
      type: Object,
      default: function () {
        return {};
      }
    },
    /**
     * @property {Object[Function]} fieldDefineProcFns - 表单属性规则处理方法集合
     */
    fieldDefineProcFns: {
      type: Object,
      default: null
    }
  },
  data() {
    return {
      disabledProperties: {},
      isSetConfigForm: false,
      loadingConfig: false,
      isChanged: false,

      finalOption: {
        menuBtn: false,
        submitBtn: false,
        clearBtn: false,
        column: []
      },

      defaultValues: {},
      formObj: {},

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

      configurations: {},
      configuration: {},

      selected: {},
      typeDicts: [],
      typeData: [],
      res: []
    };
  },
  watch: {
    data: {
      handler: function (newVal, oldVar) {
        // 父对象更新 同步到 绑定对象
        this.formObj = newVal;

        this.$emit('on-update', newVal);
      },
      immediate: true, // 刷新加载 立马触发一次 handler
      deep: true // 可以深度检测到 对象的属性值的变化
    },
    formObj(newVal) {
      if (!this.readOnly) {
        // 更新内容 同步更新到父对象
        this.$emit('update:data', newVal);
      }
    }
  },
  async created() {
    this.initOption();
    this.setConfigurationItem();
  },
  methods: {
    checkForm(callback, fallback) {
      this.$refs.form.validate((valid, done) => {
        if (valid) {
          callback && callback(done);
        } else {
          fallback && fallback();
          return false;
        }
      });
    },

    doSelect(func, row, event, option = []) {
      this[func](row, event, option);
      this.$forceUpdate();
    },

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

        await checkDataType(item);
        checkFixDic(item);

        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.isRequired === 'Y') {
              itemProp.isRequired = true;
            } else if (itemProp.isRequired === 'N') {
              itemProp.isRequired = false;
            }

            const isRequired = !!itemProp.isRequired;

            if (isRequired) {
              setRequired(item);
            }

            // 检查特定字段 固定处理
            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 || 8;

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

      return columns;
    },

    getData() {
      return JSON.parse(JSON.stringify(this.formObj));
    },

    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;
      }
    },

    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;
      }
    },

    loadedConfigruations(rows) {
      const TypeDicts = [];

      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({
        isChanged: false
      });
    },
    saveSelected(row, list, option) {
      const item = list[0];
      const matchProps = this.propMatch;

      let ref = '';

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

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

        const dataValue = item[option.dataValueProp];
        const dataName = item[option.dataNameProp];
        if (row && typeof option.valueProp !== 'undefined') {
          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 (typeof nameProp !== 'undefined') {
            row[nameProp] = '';
          }
          if (nameProp && typeof row[nameProp] !== 'undefined') {
            row[nameProp] = dataName;
          }
          const aliasProps = option.aliasProps || [];
          for (const aliasProp of aliasProps) {
            if (typeof aliasProp !== 'undefined') {
              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 (matchProps && matchProps.length) {
        matchProps.map((matchitem) => {
          if (matchitem.ref === ref) {
            row[matchitem.to] = item[matchitem.from];
          }
        });
      }

      // 手动触发验证
      if (ref && this.$refs.form) {
        this.$refs.form.validateField(ref);
      }
    },

    setConfigurationItem() {
      const config = this.configOption || {};
      const {
        name = '',
        fieldColumns = [],
        fieldPermission = [],
        rule = {}
        // height,
        // templateNumber
      } = config;

      const baseOption = {};
      const excludes = { fieldColumns: 1, fieldPermission: 1, rule: 1, templateNumber: 1 };

      const keys = Object.keys(config);

      for (const key of keys) {
        if (!excludes[key] && config[key]) {
          baseOption[key] = config[key];
        }
      }

      const configuration = {
        name,
        baseOption,
        fieldColumns: fieldColumns,
        fieldPermission: fieldPermission,
        ...rule
      };

      this.configuration = configuration;
      this.setHeadColumns();
    },

    setHeadColumns() {
      this.updateColumn();
    },

    async updateColumn(option = {}) {
      this.isSetConfigForm = false;

      const isChanged = option.isChanged;

      Object.assign(this.finalOption, this.configuration.baseOption);
      this.finalOption.column = [];
      const columns = this.finalOption.column;
      const fieldColumns = this.configuration.fieldColumns;

      const newColumn = await this.filterColum(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 valueColumns = columns.filter((column) => {
          return column.hide === true || column.disabled === 'disabled';
        });

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

        this.formObj = formEmptyValue;
      }

      this.initData();

      this.$nextTick(() => {
        this.isSetConfigForm = true;

        this.$nextTick(() => {
          this.updateFormDict(waitUpdateDic);
        });
      });
    },
    updateFormDict(dicts) {
      const form = this.$refs.form;

      if (form && form.updateDic) {
        dicts.map((prop) => {
          form.updateDic(prop);
        });
      }
    },

    setRequired(item) {
      return setRequired(item);
    }
  }
};
</script>
<style lang="scss">
@import './list.scss';
</style>
