<template>
  <ContentWrap>
    <el-form
      class="-mb-15px recipe-config-filter-form"
      :model="queryParams"
      ref="queryFormRef"
      :inline="true"
      label-width="auto"
    >
      <el-form-item :label="t('RecipeManagement.RecipeConfig.searchRecipeCodeLabel')" prop="recipeCode">
        <el-input
          v-model="queryParams.recipeCode"
          :placeholder="t('RecipeManagement.RecipeConfig.searchRecipeCodePlaceholder')"
          clearable
          @keyup.enter="handleQuery"
          class="!w-240px"
        />
      </el-form-item>
      <el-form-item :label="t('RecipeManagement.RecipeConfig.searchNameLabel')" prop="name">
        <el-input
          v-model="queryParams.name"
          :placeholder="t('RecipeManagement.RecipeConfig.searchNamePlaceholder')"
          clearable
          @keyup.enter="handleQuery"
          class="!w-240px"
        />
      </el-form-item>
      <el-form-item :label="t('RecipeManagement.RecipeConfig.searchProductNameLabel')" prop="productName">
        <el-input
          v-model="queryParams.productName"
          :placeholder="t('RecipeManagement.RecipeConfig.searchProductNamePlaceholder')"
          clearable
          @keyup.enter="handleQuery"
          class="!w-240px"
        />
      </el-form-item>

      <el-form-item>
        <el-button @click="handleQuery">
          <Icon icon="ep:search" class="mr-5px" />
          {{ t('RecipeManagement.RecipeConfig.searchButtonText') }}
        </el-button>
        <el-button @click="resetQuery">
          <Icon icon="ep:refresh" class="mr-5px" />
          {{ t('RecipeManagement.RecipeConfig.resetButtonText') }}
        </el-button>
        <el-button type="primary" plain @click="openDialog('create')">
          <Icon icon="ep:plus" class="mr-5px" />
          {{ t('RecipeManagement.RecipeConfig.createButtonText') }}
        </el-button>
        <el-button type="success" plain @click="handleExport" :loading="exportLoading">
          <Icon icon="ep:download" class="mr-5px" />
          {{ t('RecipeManagement.RecipeConfig.exportButtonText') }}
        </el-button>
      </el-form-item>
    </el-form>
  </ContentWrap>

  <ContentWrap>
    <el-table
      ref="tableRef"
      v-loading="loading"
      :data="list"
      :stripe="true"
      :show-overflow-tooltip="true"
      row-key="id"
      highlight-current-row
      @selection-change="handleSelectionChange"
      @row-click="handleRowClick"
    >
      <el-table-column type="selection" width="55" reserve-selection />
      <el-table-column
        :label="t('RecipeManagement.RecipeConfig.tableRecipeCodeColumn')"
        align="center"
        prop="recipeCode"
      />
      <el-table-column
        :label="t('RecipeManagement.RecipeConfig.tableNameColumn')"
        align="center"
        prop="name"
      />
      <el-table-column
        :label="t('RecipeManagement.RecipeConfig.tableRecipeTypeColumn')"
        align="center"
        prop="recipeType"
      >
        <template #default="scope">
          {{ getRecipeTypeLabel(scope.row.recipeType) }}
        </template>
      </el-table-column>
      <el-table-column
        :label="t('RecipeManagement.RecipeConfig.tableProductNameColumn')"
        align="center"
        prop="productName"
      />
      <el-table-column
        :label="t('RecipeManagement.RecipeConfig.tableMachineNameColumn')"
        align="center"
        prop="machineName"
      />
      <el-table-column
        :label="t('RecipeManagement.RecipeConfig.tableRecipeDescColumn')"
        align="center"
        prop="recipeDesc"
      />
      <el-table-column
        :label="t('RecipeManagement.RecipeConfig.tableOperateColumn')"
        align="center"
        width="240px"
        fixed="right"
      >
        <template #default="scope">
          <el-button link type="primary" @click.stop="openDetail(scope.row)">
            {{ t('RecipeManagement.RecipeConfig.tableConfigAction') }}
          </el-button>
          <el-button link type="primary" @click.stop="openDialog('update', scope.row)">
            {{ t('RecipeManagement.RecipeConfig.tableEditAction') }}
          </el-button>
          <el-button link type="danger" @click.stop="handleDelete(scope.row)">
            {{ t('RecipeManagement.RecipeConfig.tableDeleteAction') }}
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
      @pagination="handlePagination" />
  </ContentWrap>

  <RecipeDetailList
ref="detailRef" :visible="detailVisible"
    :recipe-id="detailMeta.id ? String(detailMeta.id) : undefined" :manual-recipe-id="detailMeta.id"
    :recipe-code="detailMeta.recipeCode" :name="detailMeta.name" @config="handleDetailConfig" @close="closeDetail" />

  <Dialog :title="dialogTitle" v-model="dialogVisible" width="720px">
    <el-form
      ref="dialogFormRef"
      :model="dialogForm"
      :rules="dialogRules"
      class="recipe-config-dialog-form"
      label-width="auto"
      v-loading="dialogLoading"
    >
      <el-form-item :label="t('RecipeManagement.RecipeConfig.dialogRecipeCodeLabel')" prop="recipeCode">
        <el-input
          v-model="dialogForm.recipeCode"
          :placeholder="t('RecipeManagement.RecipeConfig.dialogRecipeCodePlaceholder')"
          clearable
          :disabled="dialogMode == 'update'"
        />
      </el-form-item>
      <el-form-item :label="t('RecipeManagement.RecipeConfig.dialogNameLabel')" prop="name">
        <el-input
          v-model="dialogForm.name"
          :placeholder="t('RecipeManagement.RecipeConfig.dialogNamePlaceholder')"
          clearable
        />
      </el-form-item>
      <el-form-item :label="t('RecipeManagement.RecipeConfig.dialogRecipeTypeLabel')" prop="recipeTypeId">
        <el-select
          v-model="dialogForm.recipeTypeId"
          :placeholder="t('RecipeManagement.RecipeConfig.dialogRecipeTypePlaceholder')"
          clearable
          filterable
          class="!w-full"
          :loading="recipeTypeLoading"
        >
          <el-option v-for="item in recipeTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
        </el-select>
      </el-form-item>

      <el-form-item :label="t('RecipeManagement.RecipeConfig.dialogProductCategoryLabel')" prop="productCategoryId">
        <el-select
          v-model="dialogForm.productCategoryId"
          :placeholder="t('RecipeManagement.RecipeConfig.dialogProductCategoryPlaceholder')"
          clearable
          filterable
          class="!w-full"
          :loading="categoryLoading"
          @change="handleCategoryChange"
        >
          <el-option v-for="item in categoryOptions" :key="item.value" :label="item.label" :value="item.value" />
        </el-select>
      </el-form-item>
      <el-form-item :label="t('RecipeManagement.RecipeConfig.dialogProductNameLabel')" prop="productId">
        <el-select
          v-model="dialogForm.productId"
          :placeholder="t('RecipeManagement.RecipeConfig.dialogProductNamePlaceholder')"
          clearable
          filterable
          class="!w-full"
          :loading="productLoading"
          :disabled="!dialogForm.productCategoryId"
        >
          <el-option v-for="item in productOptions" :key="item.value" :label="item.label" :value="item.value" />
        </el-select>
      </el-form-item>
      <el-form-item :label="t('RecipeManagement.RecipeConfig.dialogMachineNameLabel')" prop="machineId">
        <el-select
          v-model="dialogForm.machineId"
          :placeholder="t('RecipeManagement.RecipeConfig.dialogMachineNamePlaceholder')"
          clearable
          filterable
          class="!w-full"
          :loading="deviceLoading"
          :disabled="dialogMode == 'update'"
        >
          <el-option v-for="item in deviceOptions" :key="item.value" :label="item.label" :value="item.value" />
        </el-select>
      </el-form-item>
      <el-form-item :label="t('RecipeManagement.RecipeConfig.dialogRecipeDescLabel')" prop="recipeDesc">
        <el-input
          v-model="dialogForm.recipeDesc"
          :placeholder="t('RecipeManagement.RecipeConfig.dialogRecipeDescPlaceholder')"
          clearable
          type="textarea"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="dialogVisible = false">
        {{ t('RecipeManagement.RecipeConfig.dialogCancelButton') }}
      </el-button>
      <el-button type="primary" @click="submitDialog" :disabled="dialogLoading">
        {{ t('RecipeManagement.RecipeConfig.dialogSaveButton') }}
      </el-button>
    </template>
  </Dialog>

  <Dialog :title="t('RecipeManagement.RecipeConfig.configDialogTitle')" v-model="configVisible" width="920px">
    <div v-loading="configLoading">
      <div class="formula-config-picklist">
        <div class="formula-config-panel">
          <div class="formula-config-panel__header">
            <div>{{ t('RecipeManagement.RecipeConfig.configSourceTitle') }}</div>
            <div class="formula-config-panel__meta">{{ filteredSourceItems.length }}</div>
          </div>
          <div class="formula-config-panel__filter">
            <el-input
              v-model="sourceKeyword"
              :placeholder="t('RecipeManagement.RecipeConfig.configFilterPlaceholder')"
              clearable
            />
          </div>
          <el-table
            class="formula-config-panel__table"
            :data="filteredSourceItems"
            height="440"
            :show-header="false"
            row-key="key"
            @selection-change="handleSourceSelectionChange"
            :row-class-name="getSourceRowClass"
          >
            <el-table-column type="selection" width="44" :selectable="isSourceSelectable" />
            <el-table-column prop="label" />
          </el-table>
        </div>

        <div class="formula-config-actions">
          <el-button type="primary" :disabled="!sourceCheckedKeys.length" @click="addToTarget">
            {{ t('RecipeManagement.RecipeConfig.configMoveToTargetButton') }}
          </el-button>
          <el-button :disabled="!targetCheckedKeys.length" @click="removeFromTarget">
            {{ t('RecipeManagement.RecipeConfig.configMoveToSourceButton') }}
          </el-button>
        </div>

        <div class="formula-config-panel">
          <div class="formula-config-panel__header">
            <div>{{ t('RecipeManagement.RecipeConfig.configTargetTitle') }}</div>
            <div class="formula-config-panel__meta">{{ filteredTargetItems.length }}</div>
          </div>
          <div class="formula-config-panel__filter">
            <el-input
              v-model="targetKeyword"
              :placeholder="t('RecipeManagement.RecipeConfig.configFilterPlaceholder')"
              clearable
            />
          </div>
          <el-table
            class="formula-config-panel__table"
            :data="filteredTargetItems"
            height="440"
            :show-header="false"
            row-key="key"
            @selection-change="handleTargetSelectionChange"
          >
            <el-table-column type="selection" width="44" />
            <el-table-column prop="label" />
          </el-table>
        </div>
      </div>
    </div>
    <template #footer>
      <el-button @click="configVisible = false">
        {{ t('RecipeManagement.RecipeConfig.configCancelButton') }}
      </el-button>
      <el-button type="primary" @click="submitConfig" :disabled="configLoading">
        {{ t('RecipeManagement.RecipeConfig.configSaveButton') }}
      </el-button>
    </template>
  </Dialog>
</template>

<script setup lang="ts">
import download from '@/utils/download'
import { ProductApi } from '@/api/erp/product/product'
import { ProductCategoryApi } from '@/api/erp/product/category'
import { DeviceApi } from '@/api/iot/device'
import { RecipeApi } from '@/api/iot/recipe'
import { RecipeConfigApi, RecipeConfigVO } from '@/api/iot/recipeConfig'
import RecipeDetailList from './components/RecipeDetailList.vue'

type SelectOption<T = any> = { label: string; value: T }

defineOptions({ name: 'FormulaConfig' })

const message = useMessage()
const { t } = useI18n()

const loading = ref(false)
const queryFormRef = ref()
const queryParams = reactive({
  pageNo: 1,
  pageSize: 10,
  recipeCode: '',
  name: '',
  productName: ''
})

const exportLoading = ref(false)
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: any[]) => {
  selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}

const list = ref<RecipeConfigVO[]>([])
const total = ref(0)

const buildExportParams = () => {
  const recipeCode = queryParams.recipeCode?.trim()
  const name = queryParams.name?.trim()
  const productName = queryParams.productName?.trim()
  return {
    recipeCode: recipeCode ? recipeCode : undefined,
    name: name ? name : undefined,
    productName: productName ? productName : undefined
  }
}

const buildQueryParams = () => {
  const recipeCode = queryParams.recipeCode?.trim()
  const name = queryParams.name?.trim()
  const productName = queryParams.productName?.trim()
  return {
    pageNo: queryParams.pageNo,
    pageSize: queryParams.pageSize,
    recipeCode: recipeCode ? recipeCode : undefined,
    name: name ? name : undefined,
    productName: productName ? productName : undefined
  }
}

const getList = async () => {
  loading.value = true
  try {
    const data = await RecipeConfigApi.getRecipeConfigPage(buildQueryParams())
    list.value = data.list
    total.value = data.total
  } finally {
    loading.value = false
  }
}

const handleQuery = () => {
  queryParams.pageNo = 1
  getList()
}

const resetQuery = () => {
  queryFormRef.value?.resetFields?.()
  handleQuery()
}

const handlePagination = () => {
  getList()
}

const handleExport = async () => {
  try {
    await message.exportConfirm()
    exportLoading.value = true
    const exportParams: any = {
      ...buildExportParams()
    }
    if (selectedIds.value.length) {
      exportParams.ids = selectedIds.value.join(',')
    }
    const data = await RecipeConfigApi.exportRecipeConfig(exportParams)
    download.excel(data, t('RecipeManagement.RecipeConfig.exportFileName'))
  } catch {
  } finally {
    exportLoading.value = false
  }
}

const handleDelete = async (row: RecipeConfigVO) => {
  try {
    await message.delConfirm()
    await RecipeConfigApi.deleteRecipeConfig(row.id)
    message.success(t('common.delSuccess'))
    await getList()
  } catch { }
}

const productLoading = ref(false)
const productOptions = ref<SelectOption<string>[]>([])
const categoryLoading = ref(false)
const categoryOptions = ref<SelectOption<string>[]>([])
const deviceLoading = ref(false)
const deviceOptions = ref<SelectOption<string>[]>([])
const recipeTypeLoading = ref(false)
const recipeTypeOptions = ref<SelectOption<string>[]>([])

const getRecipeTypeLabel = (value: unknown) => {
  if (value === undefined || value === null || value === '') return ''
  const matched = recipeTypeOptions.value.find(
    (item) => item.value === value || String(item.value) === String(value) || item.label === value
  )
  return matched?.label ?? String(value)
}

const getCategoryOptions = async () => {
  categoryLoading.value = true
  try {
    const data = await ProductCategoryApi.getProductCategorySimpleList()
    categoryOptions.value = (data ?? []).map((item: any) => ({ label: item.name, value: item.id }))
  } finally {
    categoryLoading.value = false
  }
}

const getProductOptions = async (categoryId: string | number | undefined) => {
  if (categoryId === undefined || categoryId === null || categoryId === '') {
    productOptions.value = []
    return
  }
  productLoading.value = true
  try {
    const data = await ProductApi.getProductSimpleList({ categoryId })
    productOptions.value = (data ?? []).map((item: any) => ({ label: item.name, value: item.id }))
  } finally {
    productLoading.value = false
  }
}

const getDeviceOptions = async () => {
  deviceLoading.value = true
  try {
    const data = await DeviceApi.getDeviceList()
    deviceOptions.value = (data ?? []).map((item: any) => ({ label: item.deviceName, value: item.id }))
  } finally {
    deviceLoading.value = false
  }
}

const getRecipeTypeOptions = async () => {
  recipeTypeLoading.value = true
  try {
    const data = await RecipeApi.getRecipePage({})
    recipeTypeOptions.value = (data?.list ?? []).map((item: any) => ({ label: item.name, value: item.id }))
  } finally {
    recipeTypeLoading.value = false
  }
}

const ensureOptionsLoaded = async () => {
  if (!categoryOptions.value.length) await getCategoryOptions()
  if (!deviceOptions.value.length) await getDeviceOptions()
  if (!recipeTypeOptions.value.length) await getRecipeTypeOptions()
}

type DialogMode = 'create' | 'update'
const dialogVisible = ref(false)
const dialogMode = ref<DialogMode>('create')
const dialogTitle = computed(() =>
  dialogMode.value === 'create'
    ? t('RecipeManagement.RecipeConfig.dialogCreateTitle')
    : t('RecipeManagement.RecipeConfig.dialogEditTitle')
)
const dialogFormRef = ref()
const dialogLoading = ref(false)
const dialogForm = reactive({
  id: undefined as number | undefined,
  recipeCode: '',
  name: '',
  recipeTypeId: '' as string | number | undefined,
  productCategoryId: '' as string | number | undefined,
  productId: '' as string | number | undefined,
  machineId: '' as string | number | undefined,
  recipeDesc: ''
})

const dialogRules = reactive({
  recipeCode: [
    {
      required: true,
      message: t('RecipeManagement.RecipeConfig.validatorRecipeCodeRequired'),
      trigger: 'blur'
    }
  ],
  name: [
    {
      required: true,
      message: t('RecipeManagement.RecipeConfig.validatorNameRequired'),
      trigger: 'blur'
    }
  ]
})

const openDialog = async (mode: DialogMode, row?: RecipeConfigVO) => {
  await ensureOptionsLoaded()
  dialogMode.value = mode
  dialogVisible.value = true
  nextTick(() => {
    dialogFormRef.value?.clearValidate?.()
  })

  if (mode === 'create') {
    dialogForm.id = undefined
    dialogForm.recipeCode = ''
    dialogForm.name = ''
    dialogForm.recipeTypeId = ''
    dialogForm.productCategoryId = ''
    dialogForm.productId = ''
    dialogForm.machineId = ''
    dialogForm.recipeDesc = ''
    productOptions.value = []
    return
  }

  dialogForm.id = row?.id
  dialogForm.recipeCode = row?.recipeCode ?? ''
  dialogForm.name = row?.name ?? row?.recipeName ?? ''
  dialogForm.recipeTypeId =
    (row as any)?.recipeTypeId ??
    (row?.recipeType === undefined || row?.recipeType === null ? '' : (row as any).recipeType)
  dialogForm.productCategoryId = (row as any)?.productCategoryId ?? (row as any)?.categoryId ?? ''

  const findProductValueByName = (name: string | undefined) => {
    if (!name) return ''
    const matched = productOptions.value.find((o) => o.label === name || String(o.value) === String((row as any)?.productId))
    return matched?.value ?? ''
  }
  const findDeviceValueByName = (name: string | undefined) => {
    if (!name) return ''
    const matched = deviceOptions.value.find((o) => o.label === name || String(o.value) === String((row as any)?.machineId ?? (row as any)?.deviceId))
    return matched?.value ?? ''
  }

  await getProductOptions(dialogForm.productCategoryId)
  dialogForm.productId = (row as any)?.productId ?? findProductValueByName(row?.productName)
  dialogForm.machineId = (row as any)?.machineId ?? (row as any)?.deviceId ?? findDeviceValueByName(row?.machineName ?? row?.deviceName)
  dialogForm.recipeDesc = row?.recipeDesc ?? row?.remark ?? ''
}

const handleCategoryChange = async (value: string | number | undefined) => {
  dialogForm.productId = ''
  await getProductOptions(value)
}

const submitDialog = async () => {
  if (!dialogFormRef.value) return
  await dialogFormRef.value.validate()
  dialogLoading.value = true
  try {
    const data = {
      id: dialogForm.id,
      recipeCode: dialogForm.recipeCode,
      name: dialogForm.name,
      recipeTypeId: dialogForm.recipeTypeId,
      productCategoryId: dialogForm.productCategoryId,
      productId: dialogForm.productId,
      machineId: dialogForm.machineId,
      recipeDesc: dialogForm.recipeDesc
    }
    if (dialogMode.value === 'create') {
      await RecipeConfigApi.createRecipeConfig(data)
      message.success(t('common.createSuccess'))
    } else {
      await RecipeConfigApi.updateRecipeConfig(data)
      message.success(t('common.updateSuccess'))
    }
    dialogVisible.value = false
    await getList()
  } finally {
    dialogLoading.value = false
  }
}

const detailRef = ref()
const detailVisible = ref(false)
const detailMeta = reactive({
  id: undefined as number | undefined,
  recipeCode: '',
  name: '',
  deviceId: undefined as number | undefined,
  machineName: ''
})

const openDetail = async (row: RecipeConfigVO) => {
  detailMeta.id = row.id
  detailMeta.recipeCode = row.recipeCode
  detailMeta.name = row.name ?? row.recipeName ?? ''
  detailMeta.deviceId = row.deviceId
  detailMeta.machineName = row.machineName ?? row.deviceName ?? ''
  detailVisible.value = true
}

const handleDetailConfig = () => {
  if (!detailMeta.id) return
  openConfigDialog(detailMeta.id)
}

const handleRowClick = async (row: RecipeConfigVO, column: any) => {
  if (column?.type === 'selection') return
  if (column?.label === t('RecipeManagement.RecipeConfig.tableOperateColumn')) return
  await openDetail(row)
}

const closeDetail = () => {
  detailVisible.value = false
  detailMeta.id = undefined
  detailMeta.recipeCode = ''
  detailMeta.name = ''
}

type TransferItem = { key: number; label: string; disabled?: boolean }

const configVisible = ref(false)
const configLoading = ref(false)
const configRecipeId = ref<string | number | undefined>(undefined)
const configCandidates = ref<TransferItem[]>([])
const configSelectedKeys = ref<number[]>([])
const configSelectedItems = ref<TransferItem[]>([])

const sourceKeyword = ref('')
const targetKeyword = ref('')
const sourceCheckedKeys = ref<number[]>([])
const targetCheckedKeys = ref<number[]>([])

const configDeviceLabel = computed(() => {
  const name = detailMeta.machineName?.trim()
  if (name) return name
  if (detailMeta.deviceId !== undefined && detailMeta.deviceId !== null) return String(detailMeta.deviceId)
  return t('RecipeManagement.RecipeConfig.configDeviceLabelFallback')
})

const normalizeKey = (value: any): number | undefined => {
  if (value === null || value === undefined || value === '') return undefined
  const n = Number(value)
  if (Number.isNaN(n)) return undefined
  return n
}

const selectedKeySet = computed(() => {
  return new Set<number>(configSelectedKeys.value ?? [])
})

const contains = (text: string, keyword: string) => {
  const k = (keyword ?? '').trim().toLowerCase()
  if (!k) return true
  return (text ?? '').toLowerCase().includes(k)
}

const filteredSourceItems = computed(() => {
  return (configCandidates.value ?? []).filter((it) => contains(it.label, sourceKeyword.value))
})

const filteredTargetItems = computed(() => {
  const set = selectedKeySet.value
  return (configCandidates.value ?? [])
    .filter((it) => set.has(it.key))
    .filter((it) => contains(it.label, targetKeyword.value))
})

const isSourceSelectable = (row: TransferItem) => {
  return !selectedKeySet.value.has(row.key)
}

const getSourceRowClass = ({ row }: { row: TransferItem }) => {
  return selectedKeySet.value.has(row.key) ? 'formula-config-row--disabled' : ''
}

const handleSourceSelectionChange = (rows: TransferItem[]) => {
  sourceCheckedKeys.value = (rows ?? []).map((r) => r.key)
}

const handleTargetSelectionChange = (rows: TransferItem[]) => {
  targetCheckedKeys.value = (rows ?? []).map((r) => r.key)
}

const addToTarget = () => {
  const next = new Set<number>(configSelectedKeys.value ?? [])
  for (const key of sourceCheckedKeys.value ?? []) next.add(key)
  configSelectedKeys.value = Array.from(next.values())
  sourceCheckedKeys.value = []
}

const removeFromTarget = () => {
  const toRemove = new Set<number>(targetCheckedKeys.value ?? [])
  configSelectedKeys.value = (configSelectedKeys.value ?? []).filter((k) => !toRemove.has(k))
  targetCheckedKeys.value = []
}

const buildTransferLabel = (item: any) => {
  return `${item.attributeName ?? item.pointName ?? ''}${item.attributeType || item.pointType ? '（' + (item.attributeType ?? item.pointType) : ''}${item.dataType ? '/' + item.dataType : ''}${item.dataUnit ? ' ' + item.dataUnit : ''}${item.attributeType || item.pointType ? '）' : ''}`
}

const loadConfigCandidatesByDevice = async (deviceId: number) => {
  const data = await DeviceApi.getDeviceAttributeList(deviceId)
  const list = (data ?? []) as any[]
  const deviceItems = (list ?? [])
    .map((item: any) => {
      const key = normalizeKey(item?.attributeId ?? item?.id)
      if (key === undefined) return undefined
      return {
        key,
        label: buildTransferLabel(item)
      } as TransferItem
    })
    .filter((it: any) => it && typeof it.key === 'number') as TransferItem[]
  configCandidates.value = deviceItems
}

const openConfigDialog = async (recipeId: number | string) => {
  configVisible.value = true
  configRecipeId.value = recipeId
  configSelectedKeys.value = []
  configCandidates.value = []
  configSelectedItems.value = []
  sourceKeyword.value = ''
  targetKeyword.value = ''
  sourceCheckedKeys.value = []
  targetCheckedKeys.value = []
  configLoading.value = true
  try {
    const selectedRes = await RecipeConfigApi.getRecipePointDetailPage({ recipeId, pageNo: 1, pageSize: 100 })
    const selectedList = Array.isArray(selectedRes) ? selectedRes : selectedRes?.list ?? selectedRes?.data ?? []
    const selectedKeys = (selectedList ?? [])
      .map((item: any) => (item.attributeId !== undefined ? item.attributeId : item.id))
      .map((id: any) => normalizeKey(id))
      .filter((id: any) => typeof id === 'number')
    configSelectedKeys.value = selectedKeys
    configSelectedItems.value = (selectedList ?? [])
      .map((item: any) => ({
        key: normalizeKey(item.attributeId !== undefined ? item.attributeId : item.id),
        label: buildTransferLabel(item)
      }))
      .filter((it: any) => typeof it.key === 'number')
    const deviceId = detailMeta.deviceId
    if (deviceId !== undefined && deviceId !== null) {
      await loadConfigCandidatesByDevice(deviceId)
    } else {
      configCandidates.value = configSelectedItems.value
    }
  } finally {
    configLoading.value = false
  }
}

const submitConfig = async () => {
  if (!configRecipeId.value) return
  configLoading.value = true
  try {
    await RecipeConfigApi.updateRecipeDeviceAttribute({ recipeId: configRecipeId.value, ids: configSelectedKeys.value })
    message.success(t('common.updateSuccess'))
    configVisible.value = false
    if (detailVisible.value && String(detailMeta.id) === String(configRecipeId.value)) {
      await detailRef.value?.refresh?.()
    }
  } finally {
    configLoading.value = false
  }
}

onMounted(() => {
  getList()
  ensureOptionsLoaded()
})
</script>

<style scoped>
.recipe-config-filter-form :deep(.el-form-item__label) {
  min-width: 68px;
}

.recipe-config-dialog-form :deep(.el-form-item__label) {
  min-width: 100px;
}

.formula-config-picklist {
  display: flex;
  width: 100%;
}

.formula-config-panel {
  width: calc((100% - 96px) / 2);
  overflow: hidden;
  background: var(--el-bg-color);
  border: 1px solid var(--el-border-color);
  border-radius: 4px;
}

.formula-config-panel__header {
  display: flex;
  padding: 10px 12px;
  font-weight: 600;
  border-bottom: 1px solid var(--el-border-color);
  justify-content: space-between;
}

.formula-config-panel__meta {
  font-weight: 400;
  color: var(--el-text-color-secondary);
}

.formula-config-panel__filter {
  padding: 10px 12px;
  border-bottom: 1px solid var(--el-border-color);
}

.formula-config-panel__table {
  width: 100%;
}

.formula-config-actions {
  display: flex;
  width: 96px;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 12px;
}

:deep(.formula-config-row--disabled) {
  opacity: 0.55;
}
</style>
