// @ts-nocheck
import AsyncValidator from 'async-validator'
import { message, Modal, FormModel } from 'ant-design-vue'
import pickValues from '../../services/pick-values'
import { getComponentSpec, getFieldDisplayExpr } from '@/common/components/sd-form'
import download from '@/common/services/download'
import axios from '@/common/services/axios-instance'
import eventHandlers from '@/application-manage/event-handlers'
function validateData(fields, datas) {
  // id字段去掉（dataType=id的字段不支持校验）
  const vFields = fields.filter((f) => f.name !== 'id' && f.dataType !== 'attachment')
  const errorMessages = FormModel.props.validateMessages.default()
  return Promise.all(
    datas.map((data) => {
      return Promise.all(
        vFields.map((field) => {
          const value =
            data[field.name] !== undefined
              ? getComponentSpec(field).parseBackendValue?.(data[field.name]) || data[field.name]
              : data[field.caption]
          const name = field.name
          let rules = []
          // 判断当前字段是否显示，显示则需要校验必填，否则不校验必填
          if (fieldDisplay(fields, data, field)) {
            rules = getRule(field)
          } else {
            rules = getRule(field, false)
          }
          const validator = new AsyncValidator({ [name]: rules })
          validator.messages(errorMessages)

          return validator
            .validate({ [name]: value })
            .then(() => {
              // 校验成功
              return true
            })
            .catch(({ errors, fields }) => {
              // 校验失败，返回字符串的 错误消息
              return `[${field.caption}]${errors[0].message}`
            })
        })
      ).then((res) => res.filter((_) => _ !== true))
    })
  )
}
export { validateData }
function getRule(field, required) {
  const rule = []
  let type = getComponentSpec(field).dataType || 'string'
  // 小数位0，视为整数
  if (field.attr.decimalPrecision === '0') type = 'integer'
  // 下拉框，视为字符串
  if (type === 'selectlist') type = 'string'

  // 必填
  required = required ?? field.required
  const baseRule = {
    type,
    required: required,
  }
  if (type === 'string' && required) {
    baseRule.whitespace = true
  }
  // 数字类型添加转换
  if (['number', 'integer', 'float', 'int', 'long'].includes(type)) {
    baseRule.transform = (value) => {
      return value ? parseFloat(value) : value
    }
  }
  rule.push(baseRule)
  // 正则
  if (field.attr.regex) {
    rule.push({
      type,
      message: field.attr.regexMessage || field.attr.invalidText,
      pattern: field.attr.regex,
    })
  }
  // 最大小长度
  if (field.attr.maxLength || field.attr.minLength) {
    rule.push({
      type,
      max: parseInt(field.attr.maxLength) || null,
      min: parseInt(field.attr.minLength) || null,
    })
  }
  // 最大小值
  if (field.attr.maxValue || field.attr.minValue) {
    const max = parseFloat(field.attr.maxValue)
    const min = parseFloat(field.attr.minValue)
    rule.push({
      type,
      max: isNaN(max) ? Infinity : max,
      min: isNaN(min) ? -Infinity : min,
    })
  }
  return rule
}

function fieldDisplay(fields, data, field) {
  // 当前字段有显示条件时，判断是否显示，是则需校验，否则不校验
  const { leftValue, rightValue, evaluator } = getFieldDisplayExpr(field)
  if (leftValue) {
    // 有条件，找到对应的条件字段
    const con = fields.find((_) => _.name === leftValue)
    if (con) {
      let value = data[con.caption]
      // 下拉框，通过label获取实际的值
      if (con.dataType === 'selectlist') {
        value = con.attr.selectListItem.find((item) => item.label === value)?.value || value
      }
      return evaluator(value, rightValue)
    }
  }
  return true
}

const sdChildTable = {
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    /**
     * 字表的值，{key:value}的格式
     */
    value: {
      type: Array,
      default: () => [],
    },
    /**
     * 字表的字段属性
     */
    fields: {
      type: Array,
      default: () => [],
    },
    /**
     * 是否只读
     */
    readOnly: {
      type: Boolean,
      default: false,
    },
    /**
     * 标签名
     */
    label: {
      type: String,
      default: '',
    },
    /**
     * 自定义子表列属性,如[{dataIndex:'shuxingmingzi15',width:'120px'}],8.0.4及以后版本支持
     */
    columns: {
      type: Array,
      default: () => [],
    },
    /**
     * 某行是否可选
     * @since 8.0.11
     */
    showSelection: {
      type: Function,
      default: () => true,
    },
    /**
     * 是否显示序号
     * @since 0.22
     */
    sequenceColumn: {
      type: Boolean,
      default: false,
    },
    /**
     * 最大行数
     *@since 8.1.0.24
     */
    max: {
      type: Number,
      default: Infinity,
    },
    /**
     * 最小行数
     *@since 8.1.0.25
     */
    min: {
      type: Number,
      default: Infinity,
    },
    /**
     * 允许Excel导入（子表只有文本、数字和单选类型的字段时支持导入）
     * @since 8.1.0.24
     */
    importable: {
      type: Boolean,
      default: false,
    },
    /**
     * @ignore
     */ formRelations: {
      type: Array,
      default: undefined,
    },
    /**
     * 禁用新建删除
     * @since 8.1.0.28
     */
    disableAd: {
      type: Boolean,
      default: false,
    },
    /**
     * @ignore
     */
    buttons: {
      type: Array,
      default: undefined,
    },
    /**
     * @ignore
     */
    events: {
      type: Array,
      default: undefined,
    },
    // 子组件接收函数
    handleBeforeAdd: {
      type: Function,
    },
    flagpage: {
      type: Boolean,
      default: false,
    },
    pages: {
      type: Number,
      default: 10,
    },
    modalWidth: {
      type: String,
      default: '1200px',
    },
    /**
     * 传给详情 modal 的 props，可以用于设置样式等
     */
    modalProps: {
      type: Object,
      default: undefined,
    },
  },
  methods: {
    getDisplayVaule(field, text) {
      if (getComponentSpec(field).getDisplayValue) {
        if (typeof text !== 'undefined' && text !== null) {
          const value = getComponentSpec(field).parseBackendValue?.(text) || text
          return getComponentSpec(field).getDisplayValue(value)
        } else {
          return ''
        }
      }
      return text
    },
    onSelectChange(selectedRowKeys) {
      this.selectedRowKeys = selectedRowKeys
    },
    exportTemplate() {
      download(
        {
          url: 'api/framework/v1/templateExport/templateExport',
          data: this.fields.filter((item) => item.dataType !== 'id' && !item.attrFD.hidden),
          method: 'post',
        },
        `${this.label ?? ''}模板.xls`
      )
    },
    importFromExcel(file) {
      if (!file.name.endsWith('.xls') && !file.name.endsWith('.xlsx')) {
        return message.warn('请导入excel文件')
      }
      var reader = new FileReader()
      reader.onload = (e) => {
        import('xlsx').then((XLSX) => {
          /* reader.readAsArrayBuffer(file) -> data will be an ArrayBuffer */
          var workbook = XLSX.read(e.target.result, { type: 'array' })
          let sheetsData = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], {
            raw: false,
          })
          if (sheetsData.length === 0) {
            return message.warn('excel为空')
          } else {
            const f = Object.keys(sheetsData[0]).some((key) => {
              return (
                this.fields.find((field) => {
                  return field.caption === key
                }) === undefined
              )
            })
            if (f) {
              return message.warn('请检查导入的excel和当前表格是否匹配')
            }
          }
          const value = []
          if (this.max - this.value.length > 0) {
            sheetsData = sheetsData.slice(0, this.max - this.value.length)
          }
          // 先校验数据
          validateData(this.fields, sheetsData).then((rows) => {
            const errRows = []
            const errIndex = []
            rows.forEach((errColumns, index) => {
              if (errColumns.length > 0) {
                errIndex.push(index)
                errRows.push({ index, errColumns })
              }
            })
            // 删除校验不通过的数据(从后往前删)
            errIndex.reverse().forEach((i) => {
              sheetsData.splice(i, 1)
            })
            // 导入校验通过的数据
            sheetsData.forEach((data) => {
              // 每行数据
              const o = {}
              this.fields.forEach((field) => {
                if (['number'].includes(field.dataType)) {
                  o[field.name] = Number(data[field.caption]) || undefined
                }
                if (['string'].includes(field.dataType)) {
                  o[field.name] = data[field.caption]?.toString()
                }
                if (['selectlist'].includes(field.dataType) && field.attr.multiple === 'false') {
                  // 从lable反找value
                  o[field.name] =
                    field.attr.selectListItem.find((item) => item.label === data[field.caption])
                      ?.value || data[field.caption]
                }
              })
              value.push(o)
            })
            this.emitValue([...this.value, ...value])

            // 有校验不通过的数据，提示
            if (errRows.length > 0) {
              Modal.warning({
                title: '部分行数据校验不通过，未导入！',
                content: errRows.map((row) => {
                  return (
                    <div class={this.$style.errorRow}>
                      第{row.index + 1}行：
                      {row.errColumns.map((e) => (
                        <span>{e}</span>
                      ))}
                    </div>
                  )
                }),
              })
            }
          })
        })
      }
      reader.readAsArrayBuffer(file)
      return false
    },
    copy(record) {
      const newValue = JSON.parse(JSON.stringify(this.fields))
      newValue.forEach((item) => {
        // 把值放到字段信息fields里
        if (item.name === 'id') return
        item.value = record[item.name]
      })
      // 拷贝附件
      const atts = newValue.filter((item) => item.dataType === 'attachment' && item.value)
      return Promise.all(
        atts.map(() => {
          return axios('api/framework/v1/attachment-extend/attachments-create-group-code')
        })
      )
        .then((groupids) => {
          return Promise.all(
            atts.map((item, index) => {
              return axios.post(
                `api/framework/v1/attachment-extend/attachments-copy/${
                  JSON.parse(item.value).value
                }/${groupids[index].data}`
              )
            })
          ).then(() => {
            atts.forEach((att, index) => {
              att.value = JSON.stringify({
                value: groupids[index].data,
              })
            })
          })
        })
        .then(() => {
          const o = {}
          newValue.forEach((item) => {
            o[item.name] = item.value
          })
          return o
        })
    },
    duplicate(keys) {
      if (this.action !== undefined && this.$options.name === 'SdChildTableInline') {
        return message.warn('请保存编辑行，再执行此操作')
      }
      const values = this.value.filter((item) => keys.includes(item.id))
      Promise.all(values.map(this.copy)).then((records) => {
        this.emitValue([...this.value, ...records])
      })
    },
    emitValue(values) {
      values.forEach((item) => {
        item.id = item.id || 'fakeId_' + Math.random()
      })
      this.$emit('change', values)
    },
    remove(keys) {
      this.selectedRowKeys = []
      this.emitValue(this.value.filter((item) => !keys.includes(item.id)))
      if (keys.includes(this.action)) {
        this.action = undefined
      }
    },
    /**
     * 获取当前选中的记录
     * @public
     * @returns {Object[]}
     * @since 8.1.0.30
     */
    getSelectedRows() {
      return this.value.filter((item) => this.selectedRowKeys.includes(item.id))
    },
    /**
     * 根据id设置记录的值
     * @public
     * @since 8.1.0.30
     */
    setRowValueById(id, value) {
      const index = this.value.findIndex((item) => item.id === id)
      if (index) {
        this.value[index] = { ...value, id }
      }
      this.emitValue(this.value)
    },
    loadEventHandlers() {
      eventHandlers.childTable.loadFrontEndHandlers().forEach((h) => {
        this.$set(this.handlers, h.id, h)
      })
    },
    buttonClick(button) {
      const context = { childTable: this }
      if (button.buttonType === 'batch') {
        // 批量按钮，获取当前选中的数据
        Object.assign(context, { selectedRows: this.getSelectedRows() })
      }
      // 获取当前按钮绑定的事件
      const event = this.events?.find((e) => e.id === button.triggerEvent)
      if (event) {
        const associateData = event.associateData
        // 循环处理事件定义的内容
        return Promise.all(
          event.eventScript?.map((e) => {
            // 获取事件处理器
            const { type, module: service } =
              this.handlers[associateData + '-' + e.eventType + '-handler'] || {}
            if (service) {
              const params = { button, eventScript: e, context }
              // vue的处理器
              if (type === 'vue') {
                this.actionComponent = service
                return service()
                  .then(() => {
                    return this.$nextTick()
                  })
                  .then(() => {
                    return this.$refs.actionComponent?.run?.(params)
                  })
              } else {
                // js的处理器
                return service().then((f) => {
                  return f.default.bind(this)(params)
                })
              }
            } else {
              return Promise.resolve()
            }
          }) || []
        )
      } else {
        message.error('未找到按钮绑定的事件')
      }
    },
    getValuesByFormulas(e, t) {
      return axios
        .post(
          'api/framework/v1/page/computeFieldValWithQLExpr',
          (t || this._inputs(this.initValues)).concat(
            e.map((e) => ({ attr: { formulaData: e }, name: 'justgetformulavalue' + e }))
          )
        )
        .then((t) => e.map((e) => t.data.find((t) => t.name === 'justgetformulavalue' + e).value))
    },
    pickerData(selector) {
      // 给选择器拼上自定义变量
      const cinputs = this.SdFormContext._inputs(this.SdFormContext.initValues)
      // 根据自定义变量的公式获取计算的值
      const customFields = JSON.parse(selector.frontData || '{}').customFields?.filter(
        (i) => i.value?.formulaData
      )
      const customValues = {}
      const customFieldsNames = customFields?.map((i) => i.name)
      const formulaDatas = customFields?.map((i) => i.value.formulaData)
      let p = Promise.resolve()
      if (formulaDatas?.length) {
        p = this.getValuesByFormulas(formulaDatas, cinputs).then((values) => {
          values.forEach((v, index) => {
            customValues[customFieldsNames[index]] = v
          })
        })
      }
      const fromForm = JSON.parse(selector.fromForm)[0]
      p.then(() =>
        import('../sd-relation-picker.vue').then(({ default: sdRelationPicker }) => {
          return pickValues(sdRelationPicker, {
            formId: fromForm.id,
            title: fromForm.name,
            isFlow: fromForm.formType === 1,
            formListId: JSON.parse(selector.fromFormList || '[]')[0]?.id,
            customValues,
          })
        })
      ).then((data) => {
        if (!data?.length) return
        Promise.all(
          data.map((params) => {
            return axios
              .get(`api/framework/v1/page/wp/onl:${fromForm.id}`, { params })
              .then((res) => res.data.pageFormData.pageFieldInfos)
          })
        ).then((datas) => {
          const childValues = []
          datas.forEach((pageFieldInfos) => {
            const childValue = {}
            JSON.parse(selector.fieldsMap).forEach((item) => {
              childValue[item.toField[0].id] = pageFieldInfos.find(
                (i) => i.name === item.fromField[0].id
              ).value
            })
            childValues.push(childValue)
          })
          // 拷贝附件
          Promise.all(childValues.map(this.copy)).then((records) => {
            this.emitValue([...this.value, ...records])
          })
        })
      })
    },
  },
  inject: {
    SdFormContext: { default: () => ({}) },
  },
  provide() {
    return {
      childTable: {
        name: this.SdFormContext.initValues?.find((field) => {
          if (this.fields[0].caption === '序号') {
            return JSON.stringify(field.attr.dync) === JSON.stringify(this.fields.shift())
          } else {
            return JSON.stringify(field.attr.dync) === JSON.stringify(this.fields)
          }
        })?.name,
        dadForm: this.SdFormContext,
      },
    }
  },
  data() {
    return {
      selectedRowKeys: [],
      visible: false,
      attkeys: {}, // 附件组件的key,行编辑了就修改对应的附件key,强制更新附件列表
      actionComponent: undefined,
      handlers: {},
      pagination: {
        current: 1,
        total: 0,
        showTotal: (total) => {
          return `总共 ${total} 条`
        },
        onChange: (page) => {
          this.pagination.current = page
          this.pageOption.startPosition = this.pageOption.maxResults * (page - 1)
          this.cardIndex = null
          this.updatedata(page)
        },
        pageSize: 10,
      }, // 分页属性
      sorter: null, // 排序属性
      defaultValue: [], // 默认数据
    }
  },
  computed: {
    allowImport() {
      const f = this.fields.filter((item) => item.dataType !== 'id')
      return (
        f.every(
          (item) =>
            ['string', 'selectlist', 'number'].includes(item.dataType) &&
            item.attr?.multiple !== 'true'
        ) &&
        f.length &&
        this.importable
      )
    },
    headerButtons() {
      return this.buttons?.filter((b) => b.buttonType !== 'inline') || []
    },
    multipleSelector() {
      // 找到来源字段都是主表的关联
      return this.formRelations?.find((item) => {
        return JSON.parse(item.fieldsMap).every((i) => !i.fromField[0].id.includes('.'))
      })
    },
  },
  watch: {
    'value.length': {
      handler(newLen) {
        // 添加了新值(长度变化了)且值中有id为null的，重新赋值(便于生成id)
        if (newLen > 0 && this.value?.some((_) => !_.id)) {
          this.emitValue([...this.value])
        }
      },
    },
  },
  created() {
    // todo先这么处理
    // 从隐藏到显示字段的只读状态也会变化，根据这个重置下子表的列宽，不reset是为了保留显示列状态
    // ，只watch一次，而且隐藏前后如果都是只读也没有这个问题
    const unwatch = this.$watch('readOnly', (newVal) => {
      if (newVal === false) {
        const f = (columns) => {
          columns.forEach((column) => {
            column.width = column.defaultWidth
            if (column.children) f(column.children)
          })
        }
        f(this.$refs.table.columnInfos)
      }
      unwatch()
    })
    // 有配置的操作按钮，加载事件处理器
    if (this.buttons?.length > 0) {
      this.loadEventHandlers()
    }
  },
}
export default sdChildTable
