<script>
import { Modal } from 'ant-design-vue'
import axios from '@/common/services/axios-instance'
import TableColumnTypes from '@/common/services/table-column-types'
import PageService from '@/common/services/page-service'
import formula2exps from './formula-2-exps'
import eventHandlers from './event-handlers'
import ApplicationService from './application-service'
import components from './_import-components/sd-list-mixin-import'

function filterFormula2Exps(formulaObj, customValues) {
  if (formulaObj) {
    formulaObj = JSON.stringify(formulaObj)
    if (typeof customValues === 'string') {
      customValues = JSON.parse(customValues)
    }
    // 把所有自定义变量的占位符替换成实际的
    Object.keys(customValues).forEach((key) => {
      let v = customValues[key]
      if (v !== undefined && v !== null) {
        if (typeof v !== 'string') v = JSON.stringify(v).replace(/"/g, '\\"')
        formulaObj = formulaObj.replace(new RegExp('{' + key + '}', 'g'), v.replace(/"/g, '\\"'))
      }
    })
    formulaObj = JSON.parse(formulaObj)
    // 过滤掉没有值的自定义变量
    const f = (o) => {
      const t = o.filter((item) => {
        if (['AND', 'OR'].includes(item.actual?.data)) {
          f(item.actual?.params)
          return true
        }
        if (item.actual?.params?.[1].actual.data.startsWith?.('{%')) {
          return true
        }
        return !item.actual?.params?.[1].actual.data.startsWith?.('{')
      })
      o.splice(0, 99)
      t.forEach((i) => o.push(i))
    }
    f(formulaObj.params)
    return formula2exps(formulaObj)
  }
}

export { filterFormula2Exps }

export default {
  name: 'SdListMixin',
  components,
  props: {
    moduleId: {
      type: String,
      default: undefined,
    },
    formListId: {
      type: String,
      default: undefined,
    },
    customValues: {
      type: [String, Object],
      default: () => ({}),
    },
  },
  data() {
    return {
      handlers: {},
      actionComponent: undefined,
      newConfig: {},
      onlListColumnDefs: [],
      formId: '',
      pageId: '',
      activeKey: '',
      tabs: [],
      customFilterExpressions: [],
      showfuzzySearch: true,
      advSearchBtnActived: false,
      pageTitle: '',
      buttons: [],
      readonly: undefined,
      scrollX: undefined,
    }
  },
  computed: {
    columns() {
      return this.onlListColumnDefs
        .filter((item) => item.show)
        .sort((a, b) => a.showSeq - b.showSeq)
        .map((item, index) => {
          let sdRender
          if (item.fieldType === 'date') {
            if (item.fieldAttr.showDate === 'true' && item.fieldAttr.showTime === 'true') {
              sdRender = TableColumnTypes.dateTime
            } else if (item.fieldAttr.showDate === 'true') {
              sdRender = TableColumnTypes.date
            } else {
              sdRender = TableColumnTypes.time
            }
          }
          return {
            title: item.fieldName,
            dataIndex: item.fieldId,
            sorter: item.sort,
            defaultSortOrder: item.sortMode,
            sdClickable: item.attrFD?.clickable ?? true,
            sdRender,
            ...item.attrFD,
            sdCandidate: item.show === 2,
          }
        })
    },
    extParams() {
      const params = {}
      this.newConfig?.defaultValues?.forEach((def) => {
        const name = JSON.parse(def.field)[0].id
        const value =
          def.opType === 'manual'
            ? def.value
            : def.opType === 'var'
            ? this.customValues[def.value]
            : undefined
        if (value !== undefined && value !== null) {
          params[name] = typeof value === 'object' ? JSON.stringify(value) : value
        }
      })
      if (Object.keys(params).length > 0) {
        return params
      }
      return undefined
    },
    configButtons() {
      return this.buttons.map((b) => {
        return {
          label: b.buttonName,
          id: b.buttonId,
          type: b.buttonType,
          permission: JSON.parse(b.actionPerm || '[]')[0]?.id || null,
          title: b.buttonDesc,
          displayExpressions: formula2exps(b.displayFormula),
          callback: (...args) => {
            return this.buttonClick(b, {
              context: { args, dataList: this.$refs[this.activeKey][0] },
            })
          },
        }
      })
    },
    fuzzyAndAdvSearch() {
      // 既有高级查询，又有模糊查询
      return this.onlListColumnDefs.some((item) => item.search) && this.searchFields?.length > 0
    },
    showAdvSearch() {
      if (this.fuzzyAndAdvSearch) {
        return this.advSearchBtnActived
      }
      return this.onlListColumnDefs.length
    },
    computeTabs() {
      return this.tabs.map((tab) => {
        return {
          ...tab,
          filterExpressions: [
            ...tab.filterExpressions,
            ...(this.filter || []),
            ...this.customFilterExpressions,
          ],
        }
      })
    },
    showSelection() {
      // 有批量按钮(删除也是批量按钮)时显示复选框
      return (
        this.actionsCompute?.filter((b) => ['batch', 'delete'].includes(b.type)).length > 0 || false
      )
    },
  },
  created() {
    this.loadEventHandlers()
  },
  methods: {
    loadListDef(isFlow) {
      if (!this.moduleId) return
      this.formId = ''
      this.onlListColumnDefs = []
      axios
        .get(
          `api/framework/v1/we-app-form-list/show?isShowChildColumn=1&appModuleId=${this.moduleId}${
            this.formListId ? '&formListId=' + this.formListId : ''
          }`
        )
        .then((res) => {
          this.pageId = res.data.pageId
          this.pageTitle = res.data.formListName
          this.formId = res.data.formId
          this.onlListColumnDefs = res.data.onlListColumnDefs
            ?.filter((item) => item.fieldAttrFD?.cid !== 'sd-linked-data')
            .sort((a, b) => a.showSeq - b.showSeq)
          this.advSearchBtnActived = res.data.attr?.defaultShowAdvSearch ?? false
          this.tabs = res.data.attr?.tabs?.map((tab, index) => {
            return {
              key: index + '',
              tab: tab.label,
              filterExpressions: formula2exps(tab.value),
            }
          })
          // 流程表单
          if (isFlow) {
            if (!this.tabs?.length) {
              this.tabs = [
                {
                  key: 'all',
                  tab: '全部',
                  filterExpressions: [],
                },
                {
                  key: 'doing',
                  tab: '办理中',
                  filterExpressions: [
                    {
                      dataType: 'int',
                      name: 'FLOW_STATUS',
                      op: 'lt',
                      intValue: 5,
                    },
                  ],
                },
                {
                  key: 'done',
                  tab: '已办结',
                  filterExpressions: [
                    {
                      dataType: 'int',
                      name: 'FLOW_STATUS',
                      op: 'eq',
                      intValue: 5,
                    },
                  ],
                },
              ]
            }
          } else {
            // 无流程表单
            this.isNewWindow = res.data.attr?.detailNewWindow
            if (!this.tabs?.length) {
              this.tabs = [
                {
                  key: 'all',
                  tab: '全部',
                  filterExpressions: [],
                },
              ]
            }
          }
          // 列表过滤公式转换为查询条件
          const filterExps = filterFormula2Exps(
            res.data.attr?.filterFormulaObject,
            this.customValues
          )
          if (filterExps) {
            this.tabs.forEach((item) => {
              item.filterExpressions = item.filterExpressions.concat(filterExps)
            })
          }
          this.activeKey = this.tabs[0].key
          this.buttons = res.data.attr?.buttons || []
          this.readonly = res.data.attr?.readonly
          this.newConfig = res.data.attr?.newConfig || {}
          this.scrollX = res.data.attr?.scrollX
        })
    },
    loadEventHandlers() {
      eventHandlers.loadFrontEndHandlers().forEach((h) => {
        this.$set(this.handlers, h.id, h)
      })
    },
    buttonClick(button, { context }) {
      let p = Promise.resolve(true)
      // 按钮点击【预警弹窗】
      if (button.isWarn === '1') {
        p = new Promise((resolve) => {
          Modal.confirm({
            content: button.warnContent,
            onOk: () => {
              resolve(true)
            },
            onCancel: () => {
              resolve(false)
            },
          })
        })
      }
      return p.then((flag) => {
        if (flag) {
          // 获取事件定义、（行内按钮）关联数据
          return Promise.all([
            button.buttonType === 'inline'
              ? PageService.get({ id: context.args[0].id }, this.pageId)
              : undefined,
            ApplicationService.getEventInfo('frontend', {
              id: button.triggerEvent,
            }),
          ]).then(([formRes, eventRes]) => {
            // 将获取到的关联数据values放到context中，便于在事件处理器中获取指定字段的数据
            const fieldInfos = formRes?.data.pageFormData?.pageFieldInfos
            if (fieldInfos) {
              context.fieldInfos = fieldInfos
            }
            const associateData = eventRes.data.associateData
            // 循环处理事件定义的内容
            return Promise.all(
              eventRes.data.methodScript?.map((e) => {
                // 获取事件处理器
                const { type, module: service } =
                  this.handlers[associateData + '-' + e.methodType + '-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()
                }
              }) || []
            )
          })
        }
      })
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
</style>
