<script lang="ts" setup>
import { sendCmd, syncSendCmd } from 'apis/system'
import SelectModal from 'components/common/SelectModal/index.vue'
import SoftKeyboard from 'components/common/SoftKeyboard/index.vue'
import { ElMessage } from 'element-plus'
import { formulaNameMap } from 'libs/constant'
import { cloneDeep } from 'lodash'
import { useHomeStore } from 'stores/homeStore'
import { computed, inject, nextTick, onMounted, ref, watch, watchEffect } from 'vue'

import { FtMessage } from '@/libs/message'
import { compareJSON, convertValuesToInt, convertValuesToString } from '@/libs/utils'
import { useFormulaStore } from '@/stores/formulaStore'

/**
 * 配方表单组件 - 用于配置和管理各种配方参数
 * 支持三种模式：主页模式(home)、设置模式(setting)和配方管理模式(formula)
 * @component
 * @props {string} type - 组件使用模式，可选值：'home' | 'setting' | 'formula'
 */

const props = defineProps<{
  type: string
  formulaNameVisible: boolean
}>()
const homeStore = useHomeStore()

const nameLeng = 10

const formulaStore = useFormulaStore()

const targetInputRef = ref<HTMLInputElement | null>(null)

const isFlip = ref(true)
/**
 * 当前表单数据
 * 不同模式下有不同的初始值：
 * - home: 当前选中的配方
 * - setting: 默认配方信息
 * - formula: 当前选中的配方或默认配方
 */
const formData = ref<Record<string, any>>({
  ...formulaStore.defaultFormulaInfo,
})

/**
 * 软键盘当前输入值
 */
const inputValue = ref<string>('')

/**
 * 软键盘是否可见
 */
const keyboardVisible = ref(false)

/**
 * 软键盘类型：'text' 或 'number'
 */
const keyboardType = ref<'text' | 'number'>('number')

/**
 * 软键盘组件引用
 */
const softKeyboardRef = ref()

/**
 * 当前聚焦的输入字段名称
 */
const focusedInput = ref<string | null>(null)

/**
 * 注册孙子组件方法的注入函数
 */
const registerGrandsonMethods = inject<(methods: any) => void>('registerGrandsonMethods', () => {})

/**
 * 配方配置列表
 */
const formulaConfigList = ref(formulaStore.formulaConfigList)

/**
 * 日志级别选项列表
 */
const options = ref(formulaStore.logLevelOptions)

/**
 * 标签单位映射表，用于显示各参数的单位
 */
const labelUnitMap: Record<string, any> = {
  injection_pump_speed: 'g/min',
  continued_gs: 'ppm',
  stoped_gs: 'ppm',
  max_humidity: '%RH',
  pre_heat_time_s: '秒',
  continued_humi: '%RH',
  stoped_humi: '%RH',
  continued_satur: '%RS',
  stoped_satur: '%RS',
  loglevel: 'Log',
}

const currentFormulaItem = ref()

/**
 * 组件挂载时注册方法供父组件调用
 */
onMounted(() => {
  registerGrandsonMethods && registerGrandsonMethods({ getFormData })
})
/**
 * 模态框是否打开
 */
const isModalOpen = ref(false)

/**
 * 打开模态框
 */
const openModal = () => {
  isModalOpen.value = true
}
const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态
/**
 * 监听配方配置列表和表单数据变化
 * 根据不同的type属性值初始化表单数据
 */
watchEffect(() => {
  formulaConfigList.value = formulaStore.formulaConfigList
  if (props.type === 'home') {
    formData.value = cloneDeep(formulaStore.selectedFormulaInfo) || cloneDeep(formulaStore.defaultFormulaInfo)
  }
  else if (props.type === 'setting') {
    formData.value = cloneDeep(formulaStore.defaultFormulaInfo)
  }
  else {
    if (formulaStore.formulaList.length === 0) {
      formData.value = cloneDeep(formulaStore.resetFormulaInfo)
    }
    else {
      formData.value = cloneDeep(formulaStore.currentSelectedFormulaInfo) || cloneDeep(formulaStore.defaultFormulaInfo)
    }
  }
  isFlip.value = formulaStore.flip
  // 后端给的数据类型是字符串型，前端需要的是int型，后端开发说（赵贺）后端不好转换，由前端进行转换.
  formData.value = convertValuesToInt(formData.value)
})

/**
 * 监听软键盘输入值变化，更新表单数据
 * @param {string | number} newVal - 新的输入值
 */
watch(inputValue, (newVal: string | number) => {
  if (focusedInput.value) {
    if (focusedInput.value !== 'name') {
      newVal = Number(newVal)
      if (currentFormulaItem.value && newVal > currentFormulaItem.value.val_upper_limit) {
        newVal = currentFormulaItem.value.val_upper_limit
      }
      formData.value[focusedInput.value] = newVal
    }
    else {
      if (newVal && newVal.toString().length > nameLeng) {
        inputValue.value = formData.value[focusedInput.value]
        return
      }
      formData.value[focusedInput.value] = newVal
    }
  }
})

/**
 * 获取当前表单数据，将值转换为字符串格式
 * @returns {Record<string, string>} 转换后的表单数据
 */
const getFormData = () => {
  return convertValuesToString(formData.value, 'name')
}

/**
 * 监听表单数据变化，同步更新软键盘输入值
 * @param {Record<string, any>} newValue - 新的表单数据
 */
watch(
  formData,
  (newValue) => {
    if (focusedInput.value) {
      inputValue.value = newValue[focusedInput.value].toString()
    }
  },
  { deep: true },
)
const formRef = ref(null)

/**
 * 处理表单提交
 * 根据不同的type属性值执行不同的保存逻辑
 */
const handleSubmit = () => {
  if (props.type !== 'setting' && !formData.value.name) {
    FtMessage.warning('请输入配方名称')
    return
  }
  // 表单验证
  if (formData.value.name && formData.value.name.length > 20) {
    FtMessage.warning('配方名称1-20字符')
    return
  }
  // 配方管理的【确定】
  if (props.type === 'formula') {
    onSaveFormula()
  }

  // 设置中的【确定】
  if (props.type === 'setting') {
    onSaveSetting()
  }
}
/**
 * @computed 计算属性 - 设备状态判断
 * @returns {boolean} - 设备是否处于空闲或已完成状态
 * @desc 控制按钮可用状态
 */
const deviceState = computed(() => {
  return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
})
/**
 * 保存配方
 * 根据是否有formula_id决定是添加新配方还是编辑已有配方
 */
const onSaveFormula = () => {
  if (formData.value.formula_id) {
    // 修改配方
    // 判断消毒是否正在执行 且正在执行配方是当前修改配方
    if (!deviceState.value && formulaStore.selectedFormulaInfo?.formula_id === formData.value.formula_id) {
      ElMessage.warning('禁止修改正在执行的配方信息!')
      return
    }
    const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name')
    onEditFormula(formulaForm.formula_id, formulaForm as Formula.FormulaItem)
  }
  else {
    // 新增配方
    onAddFormula()
  }
}

/**
 * 保存设置
 * 比较当前表单数据与默认配方数据的差异，只更新有变化的字段
 */
const onSaveSetting = async () => {
  // 修改默认值
  const diff = compareJSON(formulaStore.defaultFormulaInfo, formData.value)
  console.log(diff)
  const diffKeys = Object.keys(diff)
  if (diffKeys.length) {
    await Promise.all(
      diffKeys.map(async (key) => {
        await setSettingFormulaConfig(key, diff[key].newVal || diff[key].obj2)
      }),
    )
    FtMessage.success('配方修改成功')
  }
}

/**
 * 设置配方配置项值
 * @param {string} settingName - 设置名称
 * @param {string} settingVal - 设置值
 * @returns {Promise<void>}
 */
const setSettingFormulaConfig = async (settingName: string, settingVal: string) => {
  await sendCmd({
    className: 'SettingMgrService',
    fnName: 'setSettingVal',
    params: {
      settingName,
      settingVal: settingVal?.toString(),
    },
  })
  formulaStore.getFormualDefaultData()
}

/**
 * 添加新配方
 * 先调用API创建新配方，然后更新配方数据
 */
const onAddFormula = () => {
  const params = {
    className: 'SettingMgrService',
    fnName: 'addNewFormula',
  }
  syncSendCmd(params).then((res) => {
    if (res.ackcode === 0) {
      const item = res.rely
      const formulaForm: Record<string, any> = convertValuesToString(formData.value, 'name')
      // formulaForm.name = item.name
      formulaForm.formula_id = item.formula_id
      onEditFormula(item.formula_id, formulaForm as Formula.FormulaItem)
      formulaStore.initFormulaList()
    }
  })
}

/**
 * 编辑配方
 * @param {string} formula_id - 配方ID
 * @param {Formula.FormulaItem} formulaForm - 配方表单数据
 */
const onEditFormula = (formula_id: string, formulaForm: Formula.FormulaItem) => {
  const editParams = {
    className: 'SettingMgrService',
    fnName: 'updateFormula',
    params: {
      formula_id,
      formula: cloneDeep(formulaForm),
    },
  }
  syncSendCmd(editParams).then(() => {
    FtMessage.success('操作成功')
    formulaStore.initFormulaList()
    // formData.value = formulaForm
    formulaStore.updateSelectedFormulaData(formulaForm)
    if (
      formulaStore.selectedFormulaInfo !== null
      && formulaStore.selectedFormulaInfo.formula_id === formulaForm.formula_id
    ) {
      formulaStore.updateSelectedFormulaDataByList(formulaForm)
    }
  })
}

/**
 * 打开软键盘
 * @param {Event} e - 事件对象
 * @param item
 */
const openKeyboard = (e: any, item: Formula.FormulaItem) => {
  setTimeout(() => {
    keyboardVisible.value = true
    const labelName: string = e.target.name
    openKeyboardType(labelName)
    const formValue = formData.value[labelName]
    inputValue.value = formValue.toString()
    focusedInput.value = e.target.name
    currentFormulaItem.value = item

    const inputDom = e.target as HTMLInputElement
    targetInputRef.value = inputDom
  }, 100)
}

/**
 * 取消操作，重置配方数据
 */
// const handleCancel = () => {
//   formulaStore.initFormulaData()
// }

/**
 * 恢复默认设置
 */
const handleResetDefault = async () => {
  await sendCmd({
    className: 'SettingMgrService',
    fnName: 'factoryResetSettings',
  })
  await formulaStore.getFormualDefaultData()
}

/**
 * 确认输入值
 * @param {string} value - 输入值
 */
const handleConfirm = (value: string) => {
  console.log('确认输入:', value)
}
/**
 * 确认日志级别选择
 * @param {any} value - 选择的值
 */
const handleLogConfirm = (value: any) => {
  isModalOpen.value = false
  formData.value.loglevel = value
  formulaStore.loglevel = value
}

/**
 * 取消日志级别选择
 */
const handleLogCancel = () => {
  isModalOpen.value = false
}

/**
 * 根据标签名称确定软键盘类型
 * @param {string} labelName - 标签名称
 */
const openKeyboardType = (labelName: string) => {
  keyboardType.value = labelName === 'name' ? 'text' : 'number'
}
const size = 'default'
// 新增配方方法
const addFormula = async () => {
  const formulaInfo = cloneDeep(formulaStore.defaultFormulaInfo)
  console.log(formulaInfo)
  formData.value = formulaInfo
  await nextTick() // 等待DOM更新
  // 移除左侧列表的选中
  formData.value.name = ''
  formData.value.formula_id = null
  console.log('子组件方法被调用')
}

// 暴露方法给父组件
defineExpose({
  addFormula,
})
</script>

<template>
  <transition name="slide-right">
    <div v-if="isFlip" class="formula-form">
      <el-form
        ref="formRef"
        :disabled="type === 'home'"
        :model="formData"
        label-width="auto"
        label-position="right"
        :size="size"
        inline
      >
        <el-form-item v-if="type !== 'setting' && formulaNameVisible" label="配方名称" style="width: 93%">
          <el-input
            v-model="formData.name"
            v-prevent-keyboard
            :rules="[
              { required: true, message: '配方名称必填', trigger: 'blur' },
              { min: '1', max: '20', message: '配方名称1-20个字符', trigger: 'blur' },
            ]"
            name="name"
            prop="name"
            placeholder="配方名称"
            :disabled="type === 'home'"
            @focus="openKeyboard"
          />
        </el-form-item>
        <el-form-item
          v-for="item in formulaConfigList"
          :key="item.setting_id"
          :label="formulaNameMap[item.setting_id]"
          style="width: 50%"
        >
          <template v-if="item.val_type === 'int'">
            <el-input
              v-model.number="formData[item.setting_id]"
              v-prevent-keyboard
              style="width: 80%"
              type="number"
              :name="item.setting_id"
              :controls="false"
              :disabled="!item.is_visible_in_setting_page"
              @focus="e => openKeyboard(e, item)"
            >
              <template v-if="labelUnitMap[item.setting_id]" #append>
                {{ labelUnitMap[item.setting_id] }}
              </template>
            </el-input>
          </template>
          <template v-else-if="item.val_type === 'enum'">
            <el-input
              v-model="formData[item.setting_id]"
              v-prevent-keyboard
              style="width: 80%"
              placeholder="请选择"
              readonly
              @focus="openModal"
            >
              <template #append>
                {{ labelUnitMap[item.setting_id] }}
              </template>
            </el-input>
          </template>
          <template v-else-if="item.val_type === 'boolean'">
            <el-radio-group v-model="formData[item.setting_id]" :disabled="!item.is_visible_in_setting_page">
              <el-radio :label="true">
                是
              </el-radio>
              <el-radio :label="false">
                否
              </el-radio>
            </el-radio-group>
          </template>
        </el-form-item>
      </el-form>
      <div v-if="type !== 'home'" :style="{ marginLeft: '33%' }">
        <slot name="formulaBtn">
          <div class="default-btn">
            <el-button v-if="type === 'setting'" class="config-btn" @click="handleResetDefault">
              恢复默认值
            </el-button>
            <el-button type="primary" class="config-btn" @click="handleSubmit">
              确定
            </el-button>
          </div>
        </slot>
      </div>
      <Teleport to="body">
        <SoftKeyboard
          ref="softKeyboardRef"
          v-model="inputValue"
          :is-visible="keyboardVisible"
          :keyboard-type="keyboardType"
          :target-input="targetInputRef"
          @confirm="handleConfirm"
          @update-keyboard-visible="visible => (keyboardVisible = visible)"
          @close="keyboardVisible = false"
        />
      </Teleport>
      <SelectModal
        v-if="isModalOpen"
        :options="options"
        :selected-value="formData.loglevel"
        placeholder="请选择"
        @confirm="handleLogConfirm"
        @cancel="handleLogCancel"
      />
    </div>
  </transition>
</template>

<style lang="scss" scoped>
.formula-form {
  font-size: 20px !important;
  padding: 5px;
  padding-left: 15px;
  align-items: center;
  .default-btn {
    margin-top: 1rem;
  }
  .config-btn {
    height: 3rem;
    width: 8rem;
  }
}

.formula-form-item {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.formData-input-config {
  width: 10vw;
}
:deep(.el-input__inner) {
  text-align: left;
  height: 40px;
}
:deep(.el-form-item) {
  margin-right: 0;
  align-items: center;
}

/* 进入动画的初始状态 */
.slide-right-enter-from {
  transform: translateX(100%);
}
/* 进入动画的结束状态（也可以理解为激活状态） */
.slide-right-enter-to {
  transform: translateX(0);
}
/* 进入动画的过渡曲线等 */
.slide-right-enter-active {
  transition: transform 0.3s ease-in-out;
}
/* 离开动画的初始状态（激活状态） */
.slide-right-leave-from {
  transform: translateX(0);
}
/* 离开动画的结束状态 */
.slide-right-leave-to {
  transform: translateX(100%);
}
/* 离开动画的过渡曲线等 */
.slide-right-leave-active {
  transition: transform 0.3s ease-in-out;
}
</style>
