<!-- eslint-disable vue/no-mutating-props -->
<script setup lang="ts">
import type { VxeModalProps } from 'vxe-pc-ui'

import type { MjEditFormProps } from '../const'

import { BasicService } from '#/api/service/basic'
import hud from '#/utils/hud'
import obj from '#/utils/obj'

import {
  mj_action_add,
  mj_action_update,
  mj_form_text,
  mj_table_select,
  resetSelfItems,
} from '../const'

defineOptions({ name: 'MjEditForm' })

const props = defineProps<{
  options: MjEditFormProps
  service: BasicService
}>()

// 事件
const emit = defineEmits<{
  (e: 'editFormVisibleChanged', visible: boolean, edit: boolean): void
  // 数据修改了（添加、更新、删除成功）
  (
    e: 'dataModified',
    val: {
      action: number
      data: any
    },
  ): void
}>()

const formRef = ref()

// 编辑表单弹框
const editModalVisible = ref(false)
const defaultEditModalOptions = {
  escClosable: true,
  showMaximize: true,
} as VxeModalProps
const editModalOptions = ref(defaultEditModalOptions)

// 不需要响应式
// 重置的表单数据
let resetFormData = {} as any
// 添加表单时的默认数据
let addFormData = {} as any

// 编辑表单事件
const submit = () => {
  // 解除响应式
  let submitData = toRaw(formRef.value?.getData())
  const options = props.options

  // 添加
  const addFields = options.addFields || options.updateFields
  if (!submitData.id && addFields?.length) {
    submitData = obj.filterKeys(submitData, addFields)
  }

  // 请求前的处理
  const fn = options?.beforeSaveOrUpdate
  if (fn) {
    submitData = fn(submitData)
    if (!submitData) {
      return
    }
  }

  if (submitData.id) {
    // 如果是编辑，只更新部分字段
    let filterEditFormData = resetFormData
    const keys = props.options?.updateFields as any[]
    if (keys?.length) {
      submitData = obj.filterKeys(submitData, keys)
      filterEditFormData = obj.filterKeys(resetFormData, keys)
    }

    // 如果没有任何变化
    if (obj.isEqualIgnoreNumberString(submitData, filterEditFormData)) {
      hud.error('没有任何变化，无需提交')
      return
    }
  }

  // 保存数据
  hud.load({
    task: async () => {
      await props.service.saveOrUpdate(submitData)
    },
    success: async () => {
      editModalVisible.value = false
      emit('dataModified', {
        action: submitData.id ? mj_action_update : mj_action_add,
        data: submitData,
      })
    },
    option: '保存',
    hideSuccess: false,
  })
}

const reset = () => {
  // 内部处理
  const oldData = toRaw(formRef.value?.getData())

  // 重置
  let resetData = Object.assign({}, resetFormData)
  if (props.options?.beforeReset) {
    resetData = props.options?.beforeReset(resetData)
  }
  formRef.value?.setData(resetData)

  // 调用自定义表单控件的reset方法
  resetSelfItems(
    formRef.value?.getCurrentItems(),
    oldData,
    // 这里要get出响应式的数据
    formRef.value?.getData(),
  )
}

const formOptions = ref({} as any)

// 初始化编辑表单
function initEditForm() {
  // 弹框
  const editModalOptionsTmp = { ...defaultEditModalOptions }
  obj.cover(editModalOptionsTmp, props.options?.modal)
  editModalOptions.value = editModalOptionsTmp

  formOptions.value = props.options.form

  // 添加表单时的默认数据
  addFormData = {
    ...props.options?.defaultFormData,
  }
}

// 新增还是编辑
let isEditFormEdit = false

// 重置mj_table_select
function resetTableSelectItems(items: any[]) {
  for (const item of items) {
    if (item.children?.length) {
      // 如果有子item
      resetTableSelectItems(item.children)
      continue
    }
    const name = item.itemRender?.name
    if (name !== mj_table_select) continue
    // 调用重置
    item.itemRender.props?._methods?.reset?.()
  }
}

// 获取mj_form_text的linkedRender数据
function getLinkedRenderData(items: any[]) {
  let data = {} as any
  if (!items?.length) {
    return data
  }
  const formData = formRef.value?.getData()
  for (const item of items) {
    if (item.children?.length) {
      // 如果有子item
      data = { ...data, ...getLinkedRenderData(item.children) }
      continue
    }
    // 跳过
    const name = item.itemRender?.name
    if (name !== mj_form_text) continue
    const linkedRender = item.itemRender.props?.linkedRender
    if (!linkedRender) continue
    const fieldName = item.field
    const fieldId = fieldName.replace('Name', 'Id')
    if (formData[fieldName]) {
      data[fieldName] = formData[fieldName]
      data[fieldId] = formData[fieldId]
    } else {
      // 表单数据为空时，从linkedRender的当前选中项读取
      const selectedItems = linkedRender.props?._methods?.getSelectedItems?.()
      if (selectedItems?.length) {
        data[fieldId] = selectedItems[0].id
        data[fieldName] = selectedItems[0].name
      }
    }
  }
  return data
}

// 新增
async function add() {
  // 调整rules、items
  if (props.options?.addForm) {
    const { rules, items } = props.options.addForm
    if (rules) {
      formOptions.value.rules = rules
    }
    if (items) {
      formOptions.value.items = items
    }
  }
  editModalVisible.value = true
  await nextTick()

  isEditFormEdit = false

  // 这里直接使用引用数据
  resetFormData = Object.assign({}, addFormData)

  editModalOptions.value.title = '新增'

  // 先调用 beforeEditFormShow 确保字段可见性正确（编辑时可能隐藏了部分字段）
  let data = Object.assign({}, resetFormData)
  if (props.options?.beforeEditFormShow) {
    data = props.options.beforeEditFormShow(data, false) || data
  }

  const items = formRef.value?.getCurrentItems()
  // 重置
  resetTableSelectItems(items)
  // 初始化添加界面的数据
  const initData = getLinkedRenderData(items)

  // 复制对象，避免修改原数据
  data = Object.assign(initData, data)
  formRef.value?.setData(data)
}

// 编辑
async function edit(row: any) {
  // 调整rules、items
  if (props.options?.updateForm) {
    const { rules, items } = props.options.updateForm
    if (rules) {
      formOptions.value.rules = rules
    }
    if (items) {
      formOptions.value.items = items
    }
  }
  editModalVisible.value = true
  await nextTick()

  isEditFormEdit = true

  resetFormData = Object.assign({}, row)

  editModalOptions.value.title = '编辑'
  // 复制对象，避免修改原数据
  let data = Object.assign({}, resetFormData)
  if (props.options?.beforeEditFormShow) {
    data = props.options.beforeEditFormShow(data, true)
  }
  formRef.value?.setData(data)
}

// 监听表单对话框的显示和隐藏
watch(
  () => editModalVisible.value,
  (visible) => {
    emit('editFormVisibleChanged', visible, isEditFormEdit)

    if (!visible && props.options?.onEditFormHide) {
      props.options.onEditFormHide(isEditFormEdit)
    }
  },
)

watch(
  () => props,
  () => {
    initEditForm()
  },
  {
    immediate: true,
    // 深度监听
    deep: true,
  },
)

defineExpose({
  add,
  edit,
  hideItems(fields: any) {
    formRef.value?.hideItems(fields)
  },
  showItems(fields: any) {
    formRef.value?.showItems(fields)
  },
  update(data: any) {
    formRef.value?.updateData(data)
  },
  getData() {
    return formRef.value?.getData() || formOptions.value.data
  },
  getOptions() {
    return formRef.value?.getOptions()
  },
})
</script>

<template>
  <!-- 如果给vxe-modal加class属性，会报错：
   [Vue warn]: Extraneous non-props attributes (class) were passed to component
   but could not be automatically inherited
   because component renders fragment or text or teleport root nodes. -->
  <vxe-modal v-model="editModalVisible" v-bind="editModalOptions">
    <template #default>
      <mj-form
        ref="formRef"
        :options="formOptions"
        @submit="submit"
        @reset="reset"
        show-reset
      >
        <template v-for="(_, slotName) in $slots" #[slotName]="slotProps">
          <slot :name="slotName" v-bind="slotProps || {}"></slot>
        </template>
      </mj-form>
    </template>
  </vxe-modal>

  <!-- <mj-modal v-model="editModalVisible" :options="editModalOptions">
    <mj-form
      ref="formRef"
      :options="options.form"
      @submit="submit"
      @reset="reset"
    >
      <template v-for="(_, slotName) in $slots" #[slotName]="slotProps">
        <slot :name="slotName" v-bind="slotProps || {}"></slot>
      </template>
    </mj-form>
  </mj-modal> -->
</template>

<style lang="scss" scoped></style>
