<template>
  <Dialog :title="dialogTitle" v-model="dialogVisible" width="800px">
    <el-form
      ref="formRef"
      :model="formData"
      :rules="formRules"
      label-width="100px"
      v-loading="formLoading"
    >
      <el-form-item label="表编码" prop="code">
        <el-input v-model="formData.code" placeholder="请输入表编码" :disabled="formType === 'update'" />
      </el-form-item>

      <el-form-item label="表名称" prop="name">
        <el-input v-model="formData.name" placeholder="请输入表名称" />
      </el-form-item>

      <el-form-item label="能源类型" prop="deviceTypeId">
        <el-select
          v-model="formData.deviceTypeId"
          @change="handleDeviceTypeChange"
          placeholder="请选择能源类型"
          clearable
          filterable
          class="!w-full"
        >
          <el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.id" />
        </el-select>
      </el-form-item>

      <el-form-item label="所属区域" prop="orgId">
        <el-tree-select
          v-model="formData.orgId"
          :data="orgSelectTree"
          :props="orgTreeSelectProps"
          filterable
          check-strictly
          clearable
          class="!w-full"
          placeholder="根据区域结构筛选列表"
          :loading="analysisLoading"
          :render-after-expand="false"
          @change="handleOrgChange"
        />
      </el-form-item>

      <el-form-item label="计算规则" prop="operationRulesVOList">
        <div class="w-full flex flex-col gap-8px">
          <div
            v-for="(rule, index) in formData.operationRulesVOList"
            :key="index"
            class="w-full flex items-center gap-8px"
          >
            <el-tree-select
              v-model="rule.pointValue"
              :data="equipmentTree"
              :props="treeSelectProps"
              filterable
              clearable
              class="!w-full"
              placeholder="根据设备选择点位"
              :disabled="!formData.orgId"
              @change="(val) => handlePointSelected(index, val)"
            />

            <template v-if="index < formData.operationRulesVOList.length - 1">
              <el-select
                v-model="formData.operationRulesVOList[index].operator"
                placeholder="运算符"
                class="!w-110px"
                clearable
              >
                <el-option v-for="op in operatorOptions" :key="op" :label="op" :value="op" />
              </el-select>
            </template>
            <template v-else>
              <div class="flex items-center gap-4px">
                <el-button link type="primary" @click="addRule">
                  <Icon icon="ep:plus" />
                </el-button>
                <el-button
                  link
                  type="danger"
                  :disabled="formData.operationRulesVOList.length <= 1"
                  @click="removeRule"
                >
                  <el-icon><Remove /></el-icon>
                </el-button>
              </div>
            </template>
          </div>
        </div>
      </el-form-item>

      <el-form-item label="是否启用" prop="isEnable">
        <el-switch v-model="formData.isEnable" />
      </el-form-item>
    </el-form>
    <!-- <el-form-item label="信息资料" prop="info">
      <Editor v-model="formData.info" height="250px" />
    </el-form-item> -->
    <template #footer>
      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
</template>
<script setup lang="ts">
import { EnergyDeviceApi, EnergyDeviceVO } from '@/api/mes/energydevice'
import {EnergyTypeApi, EnergyTypeVO} from "@/api/mes/energytype";
import { OrganizationApi, DeviceParameterAnalysisNodeVO } from '@/api/mes/organization'
import { Remove } from '@element-plus/icons-vue'
import { handleTree } from '@/utils/tree'

/** 能源设备 表单 */
defineOptions({ name: 'EnergyDeviceForm' })

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const typeList = ref<EnergyTypeVO[]>([]) // 列表
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formType = ref('') // 表单的类型：create - 新增；update - 修改
const formData = ref({
  id: undefined,
  name: undefined,
  code: undefined,
  deviceTypeId: undefined,
  deviceTypeName: undefined,
  info: undefined,
  checkCron: undefined,
  lastCheckTime: undefined,
  lastCheckValue: undefined,
  unitName: undefined,
  isEnable: undefined,
  orgId: undefined,
  orgName: undefined,
  rules: undefined,
  operationRulesVOList: [{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }],
})
const formRules = reactive({
  name: [{ required: true, message: '表名称不能为空', trigger: 'blur' }],
  code: [{ required: true, message: '表编码不能为空', trigger: 'blur' }],
  orgId: [{ required: true, message: '所属区域不能为空', trigger: 'change' }],
  operationRulesVOList: [{ required: true, validator: (_rule, _value, callback) => validateRules(callback), trigger: 'change' }],
  isEnable: [{ required: true, message: '是否启用不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref

const analysisLoading = ref(false)
type OrgAnalysisNode = DeviceParameterAnalysisNodeVO & { children?: OrgAnalysisNode[] }

const analysisList = ref<OrgAnalysisNode[]>([])

const analysisTree = computed(() => {
  const list = analysisList.value ?? []
  if (!list.length) return [] as OrgAnalysisNode[]

  const hasParentId = list.some((n) => (n as any).parentId !== undefined && (n as any).parentId !== null)
  if (!hasParentId) {
    return list.map((n) => ({ ...n })) as OrgAnalysisNode[]
  }

  const cloned = list.map((n) => ({ ...n })) as OrgAnalysisNode[]
  return handleTree(cloned as any[], 'id', 'parentId', 'children') as OrgAnalysisNode[]
})

type OrgSelectNode = {
  id: number | string
  name: string
  children?: OrgSelectNode[]
}

const orgSelectTree = computed(() => {
  const tree = analysisTree.value ?? []
  if (!tree.length) return [] as OrgSelectNode[]

  const pruneAndAttach = (nodes: OrgAnalysisNode[]): OrgSelectNode[] => {
    const kept: OrgSelectNode[] = []
    nodes.forEach((node) => {
      const childNodes = Array.isArray(node.children) ? pruneAndAttach(node.children) : []
      const hasValidEquipment = (node?.equipments ?? []).some((eq) => (eq?.parameters ?? []).length > 0)
      if (!hasValidEquipment && !childNodes.length) return
      kept.push({ id: node.id, name: node.name, children: childNodes.length ? childNodes : undefined })
    })
    return kept
  }

  return pruneAndAttach(tree)
})

const orgTreeSelectProps = {
  label: 'name',
  children: 'children',
  value: 'id'
}

const treeSelectProps = {
  label: 'name',
  children: 'children',
  disabled: 'disabled',
  value: 'id'
}

const operatorOptions = ['+', '-', '*', '/']

const currentOrgNode = computed(() => {
  return analysisList.value.find((o) => o.id === formData.value.orgId)
})

const equipmentTree = computed(() => {
  const equipments = currentOrgNode.value?.equipments ?? []
  return equipments
    .map((eq) => {
      const params = eq.parameters ?? []
      if (!params.length) return null
      return {
        id: `device:${eq.id}`,
        name: eq.name,
        disabled: true,
        children: params.map((p) => ({
          id: `${eq.id}:${p.id}`,
          name: `${eq.name}: ${p.name}`
        }))
      }
    })
    .filter(Boolean) as any[]
})

/** 打开弹窗 */
const open = async (type: string, id?: number) => {
  dialogVisible.value = true
  dialogTitle.value = t('action.' + type)
  formType.value = type
  resetForm()

  await loadAnalysis()
  // 修改时，设置数据
  if (id) {
    formLoading.value = true
    try {
      formData.value = await EnergyDeviceApi.getEnergyDevice(id)
      if (!Array.isArray((formData.value as any).operationRulesVOList)) {
        ;(formData.value as any).operationRulesVOList = [
          { deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }
        ]
      }
      hydratePointValues()
    } finally {
      formLoading.value = false
    }
  }
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件，用于操作成功后的回调
const submitForm = async () => {
  // 校验表单
  await formRef.value.validate()
  // 提交请求
  formLoading.value = true
  try {
    const data = formData.value as unknown as EnergyDeviceVO
    data.deviceTypeName =  typeList.value.find(item => item.id === data.deviceTypeId)?.name

    const org = analysisList.value.find((o) => o.id === data.orgId)
    if (org) {
      ;(data as any).orgName = org.name
    }

    ;(data as any).operationRulesVOList = buildOperationRulesPayload()

    if (formType.value === 'create') {
      await EnergyDeviceApi.createEnergyDevice(data)
      message.success(t('common.createSuccess'))
    } else {
      await EnergyDeviceApi.updateEnergyDevice(data)
      message.success(t('common.updateSuccess'))
    }
    dialogVisible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/** 重置表单 */
const resetForm = () => {
  formData.value = {
    id: undefined,
    name: undefined,
    code: undefined,
    deviceTypeId: undefined,
    deviceTypeName: undefined,
    info: undefined,
    checkCron: undefined,
    lastCheckTime: undefined,
    lastCheckValue: undefined,
    unitName: undefined,
    isEnable: true,
    orgId: undefined,
    orgName: undefined,
    rules: undefined,
    operationRulesVOList: [{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }]
  }
  formRef.value?.resetFields()
}

/** 初始化 **/
onMounted(async () => {
  typeList.value = await EnergyTypeApi.getEnergyTypeList()
})

const loadAnalysis = async () => {
  if (analysisList.value.length > 0) {
    return
  }
  analysisLoading.value = true
  try {
    analysisList.value = await OrganizationApi.deviceParameterAnalysis({})
  } finally {
    analysisLoading.value = false
  }
}

const handleDeviceTypeChange = () => {
  formData.value.unitName = typeList.value.find(item => item.id === formData.value.deviceTypeId)?.unit
}

const handleOrgChange = () => {
  const org = analysisList.value.find((o) => o.id === formData.value.orgId)
  formData.value.orgName = org?.name
  formData.value.operationRulesVOList = [
    { deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }
  ]
}

const handlePointSelected = (index: number, val: any) => {
  if (!val || typeof val !== 'string' || !val.includes(':')) {
    formData.value.operationRulesVOList[index].deviceId = undefined
    formData.value.operationRulesVOList[index].pointId = undefined
    return
  }
  const [deviceIdStr, pointIdStr] = val.split(':')
  const deviceId = Number(deviceIdStr)
  const pointId = Number(pointIdStr)
  formData.value.operationRulesVOList[index].deviceId = Number.isNaN(deviceId) ? undefined : deviceId
  formData.value.operationRulesVOList[index].pointId = Number.isNaN(pointId) ? undefined : pointId
}

const addRule = () => {
  formData.value.operationRulesVOList.push({
    deviceId: undefined,
    pointId: undefined,
    operator: undefined,
    pointValue: undefined
  })
}

const removeRule = () => {
  if (formData.value.operationRulesVOList.length <= 1) {
    return
  }
  formData.value.operationRulesVOList.pop()
}

const buildOperationRulesPayload = () => {
  const list = (formData.value.operationRulesVOList ?? []).map((r, idx) => {
    const item: any = {
      deviceId: r.deviceId,
      pointId: r.pointId
    }
    if (r.operator) {
      item.operator = r.operator
    }
    return item
  })
  return list
}

const hydratePointValues = () => {
  const list = (formData.value as any).operationRulesVOList as any[]
  if (!Array.isArray(list)) {
    return
  }
  list.forEach((r) => {
    if (r?.deviceId && r?.pointId) {
      r.pointValue = `${r.deviceId}:${r.pointId}`
    }
  })
}

const validateRules = (callback: any) => {
  const list = formData.value.operationRulesVOList ?? []
  if (!list.length) {
    callback(new Error('计算规则不能为空'))
    return
  }
  for (let i = 0; i < list.length; i++) {
    const r = list[i] as any
    if (!r?.deviceId || !r?.pointId) {
      callback(new Error('请选择设备点位'))
      return
    }
    if (i > 0 && !list[i - 1]?.operator) {
      callback(new Error('请选择运算符'))
      return
    }
  }
  callback()
}
</script>
