<template>
  <Dialog :title="dialogTitle" v-model="dialogVisible" width="1000px">
    <el-form
      ref="formRef"
      :model="formData"
      :rules="formRules"
      label-width="120px"
      v-loading="formLoading"
    >
      <el-form-item :label="t('ProductionPlan.Plan.dialogTaskLabel')" prop="taskId">
        <el-select
          disabled
          v-model="formData.taskId"
          clearable
          filterable
          :placeholder="t('ProductionPlan.Plan.dialogTaskPlaceholder')"
          @change="handleTaskChange"
        >
          <el-option v-for="item in taskList" :key="item.id" :label="item.code" :value="item.id" />
        </el-select>
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogTaskDetailLabel')" prop="taskDetailId">
        <el-select
          disabled
          v-model="formData.taskDetailId"
          clearable
          filterable
          :placeholder="t('ProductionPlan.Plan.dialogTaskDetailPlaceholder')"
          @change="handleTaskDetailChange"
        >
          <el-option
            v-for="item in taskDetailList"
            :key="item.id"
            :label="`${item.productName}-${t('ProductionPlan.Plan.dialogTaskDetailUnplannedPrefix')}${Number(item.number || 0) - Number(item.planNumber || 0)}`"
            :value="item.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item prop="code">
        <template #label>
          <span>
            {{ t('ProductionPlan.Plan.dialogCodeLabel') }}
            <el-tooltip :content="t('ProductionPlan.Plan.dialogCodeTooltip')" placement="top">
              <Icon icon="ep:question-filled" />
            </el-tooltip>
          </span>
        </template>
        <el-row :gutter="10" class="!w-full">
          <el-col :xs="24" :sm="18" :md="16" :lg="14" :xl="12">
            <el-input
              :disabled="formData.isCode === true || formType === 'update'"
              v-model="formData.code"
              :placeholder="t('ProductionPlan.Plan.dialogCodePlaceholder')"
            />
          </el-col>
          <el-col :xs="24" :sm="6" :md="4" :lg="3" :xl="2">
            <el-switch v-model="formData.isCode" :disabled="formType === 'update'" />
          </el-col>
        </el-row>
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogDeliveryDateLabel')">
        <el-input :model-value="deliveryDateText" disabled />
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogProcessRouteLabel')" prop="processRouteId">
        <el-input
          :model-value="processRouteDisplayName"
          disabled
          :placeholder="t('ProductionPlan.Plan.dialogProcessRouteEmptyText')"
        />
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogProcessRouteItemsLabel')">
        <el-table
          :data="formData.processRouteItems"
          border
          size="small"
          row-key="processRouteItemId"
          class="process-route-items-table"
          :empty-text="t('ProductionPlan.Plan.dialogProcessRouteEmptyText')"
        >
          <el-table-column :label="t('ProductionPlan.Plan.routeItemSortColumn')" prop="sort" width="70" align="center" />
          <el-table-column
            :label="t('ProductionPlan.Plan.routeItemParameterCodeColumn')"
            prop="processParameterCode"
            min-width="140"
            align="center"
          />
          <el-table-column
            :label="t('ProductionPlan.Plan.routeItemParameterNameColumn')"
            prop="processParameterName"
            min-width="160"
            align="center"
          />
          <el-table-column :label="t('ProductionPlan.Plan.routeItemRemarkColumn')" prop="remark" min-width="140" align="center" />
          <el-table-column :label="t('ProductionPlan.Plan.routeItemDeviceColumn')" min-width="240" align="center">
            <template #default="scope">
              <el-input
                :model-value="getRouteItemDeviceDisplay(scope.row)"
                :placeholder="t('ProductionPlan.Plan.routeItemDevicePlaceholder')"
                readonly
                clearable
                @click="openDeviceSelectDialog(scope.row)"
                @clear="clearRouteItemDevice(scope.row)"
              >
                <template #append>
                  <el-button @click.stop="openDeviceSelectDialog(scope.row)">
                    {{ t('ProductionPlan.Plan.routeItemDeviceSelectButton') }}
                  </el-button>
                </template>
              </el-input>
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogPlanNumberLabel')" prop="planNumber">
        <el-input v-model="formData.planNumber" />
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogPlanStartLabel')" prop="planStartTime">
        <el-date-picker
          v-model="formData.planStartTime"
          type="datetime"
          value-format="x"
          :placeholder="t('ProductionPlan.Plan.dialogPlanStartPlaceholder')"
          class="!w-full"
          @change="handlePlanStartTimeChange"
        />
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogPlanEndLabel')" prop="planEndTime">
        <el-date-picker
          v-model="formData.planEndTime"
          type="datetime"
          value-format="x"
          :placeholder="t('ProductionPlan.Plan.dialogPlanEndPlaceholder')"
          class="!w-full"
          @change="handlePlanEndTimeChange"
        />
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogLatestStartLabel')" prop="latestStartTime">
        <el-date-picker
          v-model="formData.latestStartTime"
          type="datetime"
          value-format="x"
          :disabled-date="latestStartDisabledDate"
          :placeholder="t('ProductionPlan.Plan.dialogLatestStartPlaceholder')"
          class="!w-full"
        />
      </el-form-item>
      <el-form-item :label="t('ProductionPlan.Plan.dialogRemarkLabel')" prop="remark">
        <el-input
          type="textarea"
          v-model="formData.remark"
          :placeholder="t('ProductionPlan.Plan.dialogRemarkPlaceholder')"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="submitForm" type="primary" :disabled="formLoading">
        {{ t('ProductionPlan.Plan.dialogSubmitButtonText') }}
      </el-button>
      <el-button @click="dialogVisible = false">
        {{ t('ProductionPlan.Plan.dialogCancelButtonText') }}
      </el-button>
    </template>
  </Dialog>
  <TableSelectDialog
    ref="deviceSelectDialogRef"
    :title="t('ProductionPlan.Plan.selectDeviceDialogTitle')"
    :columns="deviceColumns"
    :fetch-api="fetchDeviceLedgerPage"
    selection-type="single"
    row-key="id"
    @confirm="handleDeviceSelectConfirm"
  />
</template>

<script setup lang="ts">
import dayjs from 'dayjs'
import { PlanApi, PlanProcessRouteItemVO, PlanVO } from '@/api/mes/plan'
import { TaskApi, TaskDetailVO, TaskVO } from '@/api/mes/task'
import { DeviceLedgerApi } from '@/api/mes/deviceledger'
import { ErpProductCategoryProcessRouteItemRespVO, ProductApi } from '@/api/erp/product/product'
import TableSelectDialog from '@/components/TableSelectDialog/TableSelectDialog.vue'

defineOptions({ name: 'PlanForm' })

type PlanFormData = Partial<PlanVO> & {
  isCode?: boolean
  finishDate?: string | number
  deliveryDate?: string | number
  processRouteItems?: PlanProcessRouteItemVO[]
}

const taskList = ref<TaskVO[]>([])
const taskDetailList = ref<TaskDetailVO[]>([])
const maxUnplannedNumber = ref<number | undefined>(undefined)

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

const dialogVisible = ref(false)
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formData = ref<PlanFormData>({})
const formRef = ref()
const deviceSelectDialogRef = ref()
const activeRouteItemRow = ref<PlanProcessRouteItemVO>()

const deliveryDateText = computed(() => {
  const sourceValue = formData.value.finishDate || formData.value.deliveryDate
  if (!sourceValue) return ''
  const value = dayjs(sourceValue)
  if (!value.isValid()) return String(sourceValue)
  return value.format('YYYY-MM-DD')
})

const processRouteDisplayName = computed(() => {
  if (!formData.value.processRouteId) return ''
  return formData.value.processRouteName || String(formData.value.processRouteId)
})

const latestStartDisabledDate = (date: Date) => {
  if (!formData.value.finishDate) return false
  const deliveryDate = dayjs(formData.value.finishDate)
  if (!deliveryDate.isValid()) return false
  return dayjs(date).startOf('day').valueOf() > deliveryDate.startOf('day').valueOf()
}

const validateLatestStartTime = (_rule: any, value: any, callback: (error?: Error) => void) => {
  if (!value || !formData.value.finishDate) {
    callback()
    return
  }
  const latestStart = dayjs(value)
  const deliveryDate = dayjs(formData.value.finishDate)
  if (!latestStart.isValid() || !deliveryDate.isValid()) {
    callback()
    return
  }
  if (latestStart.startOf('day').valueOf() > deliveryDate.startOf('day').valueOf()) {
    callback(new Error(t('ProductionPlan.Plan.validatorLatestStartAfterDelivery')))
    return
  }
  callback()
}

const validatePlanStartTime = (_rule: any, value: any, callback: (error?: Error) => void) => {
  if (!value || !formData.value.planEndTime) {
    callback()
    return
  }
  const startTime = Number(value)
  const endTime = Number(formData.value.planEndTime)
  if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
    callback()
    return
  }
  if (startTime > endTime) {
    callback(new Error(t('ProductionPlan.Plan.validatorPlanStartBeforeEnd')))
    return
  }
  callback()
}

const validatePlanEndTime = (_rule: any, value: any, callback: (error?: Error) => void) => {
  if (!value || !formData.value.planStartTime) {
    callback()
    return
  }
  const endTime = Number(value)
  const startTime = Number(formData.value.planStartTime)
  if (Number.isNaN(endTime) || Number.isNaN(startTime)) {
    callback()
    return
  }
  if (endTime < startTime) {
    callback(new Error(t('ProductionPlan.Plan.validatorPlanEndAfterStart')))
    return
  }
  callback()
}

const getSelectedTaskDetailUnplanned = () => {
  const detail = taskDetailList.value.find(
    (item: any) => Number(item.id) === Number(formData.value.taskDetailId)
  ) as any
  if (!detail) return undefined
  const total = Number(detail.number)
  const planned = Number(detail.planNumber)
  if (!Number.isFinite(total) || !Number.isFinite(planned)) return undefined
  return Math.max(total - planned, 0)
}

const getPlanNumberLimit = () => {
  const detailUnplanned = getSelectedTaskDetailUnplanned()
  if (detailUnplanned !== undefined) return detailUnplanned
  return maxUnplannedNumber.value
}

const validatePlanNumber = (_rule: any, value: any, callback: (error?: Error) => void) => {
  if (value === undefined || value === null || value === '') {
    callback()
    return
  }
  const currentPlanNumber = Number(value)
  if (!Number.isFinite(currentPlanNumber)) {
    callback(new Error(t('ProductionPlan.Plan.validatorPlanNumberNumeric')))
    return
  }
  const planNumberLimit = getPlanNumberLimit()
  if (planNumberLimit !== undefined && currentPlanNumber > planNumberLimit) {
    callback(new Error(t('ProductionPlan.Plan.validatorPlanNumberLimit', { limit: planNumberLimit })))
    return
  }
  callback()
}

const formRules = reactive({
  taskDetailId: [{ required: true, message: t('ProductionPlan.Plan.validatorTaskDetailRequired'), trigger: 'blur' }],
  taskId: [{ required: true, message: t('ProductionPlan.Plan.validatorTaskRequired'), trigger: 'blur' }],
  planNumber: [
    { required: true, message: t('ProductionPlan.Plan.validatorPlanNumberRequired'), trigger: 'blur' },
    { validator: validatePlanNumber, trigger: ['blur', 'change'] }
  ],
  planStartTime: [
    { required: true, message: t('ProductionPlan.Plan.validatorPlanStartRequired'), trigger: 'blur' },
    { validator: validatePlanStartTime, trigger: 'change' }
  ],
  planEndTime: [
    { required: true, message: t('ProductionPlan.Plan.validatorPlanEndRequired'), trigger: 'blur' },
    { validator: validatePlanEndTime, trigger: 'change' }
  ],
  latestStartTime: [
    { required: true, message: t('ProductionPlan.Plan.validatorLatestStartRequired'), trigger: 'blur' },
    { validator: validateLatestStartTime, trigger: 'change' }
  ]
})

const deviceColumns = [
  { label: t('ProductionPlan.Plan.deviceColumnCode'), prop: 'deviceCode', minWidth: 140 },
  { label: t('ProductionPlan.Plan.deviceColumnName'), prop: 'deviceName', minWidth: 160 },
  { label: t('ProductionPlan.Plan.deviceColumnModel'), prop: 'deviceModel', minWidth: 140 },
  { label: t('ProductionPlan.Plan.deviceColumnWorkshop'), prop: 'workshopName', minWidth: 140 }
]

const fetchDeviceLedgerPage = (params: Record<string, any>) => {
  return DeviceLedgerApi.getDeviceLedgerPage({
    ...params,
    isScheduled: 1
  })
}

const getRouteItemDeviceDisplay = (row: PlanProcessRouteItemVO) => {
  if (!row?.deviceId) return ''
  return row.deviceName || String(row.deviceId)
}

const openDeviceSelectDialog = (row: PlanProcessRouteItemVO) => {
  activeRouteItemRow.value = row
  const rows = row.deviceId
    ? [
        {
          id: Number(row.deviceId),
          deviceName: row.deviceName
        }
      ]
    : []
  deviceSelectDialogRef.value?.open(rows)
}

const handleDeviceSelectConfirm = (payload: { ids: (number | string)[]; rows: any[] }) => {
  const row = payload.rows?.[0]
  if (!row || !activeRouteItemRow.value) return
  const deviceId = Number(row.id)
  if (!Number.isFinite(deviceId)) return
  activeRouteItemRow.value.deviceId = deviceId
  activeRouteItemRow.value.deviceName = row.deviceName || row.name || row.code || `ID:${deviceId}`
}

const clearRouteItemDevice = (row: PlanProcessRouteItemVO) => {
  row.deviceId = undefined
  row.deviceName = undefined
}

const syncFinishDateByTaskDetail = () => {
  const detail = taskDetailList.value.find((item: any) => Number(item.id) === Number(formData.value.taskDetailId)) as any
  formData.value.finishDate = detail?.finishDate || detail?.deliveryDate || undefined
  formData.value.deliveryDate = detail?.deliveryDate || formData.value.deliveryDate
}

const normalizeProcessRouteItems = (items?: Array<ErpProductCategoryProcessRouteItemRespVO | PlanProcessRouteItemVO>) => {
  if (!Array.isArray(items)) return []
  return items.map((item, index) => ({
    id: (item as any).id,
    categoryId: (item as any).categoryId,
    processRouteId: (item as any).processRouteId,
    processRouteItemId: (item as any).processRouteItemId || (item as any).id,
    sort: item.sort || index + 1,
    processParameterId: item.processParameterId,
    processParameterCode: item.processParameterCode,
    processParameterName: item.processParameterName,
    remark: item.remark,
    deviceId: (item as any).deviceId,
    deviceName: (item as any).deviceName
  }))
}

const loadProductProcessRoute = async (productId?: number | string) => {
  formData.value.processRouteId = undefined
  formData.value.processRouteName = undefined
  formData.value.processRouteItems = []
  if (!productId) return
  const data = await ProductApi.getProductProcessRoute(productId)
  formData.value.processRouteId = data?.processRouteId
  formData.value.processRouteName = data?.processRouteName
  formData.value.processRouteItems = normalizeProcessRouteItems(data?.processRouteItems)
}

const open = async (
  type: string,
  id?: number,
  taskId?: number,
  productId?: number,
  number?: number,
  taskDetailId?: string,
  taskDeliveryDate?: string | number
) => {
  dialogVisible.value = true
  dialogTitle.value = t('action.' + type)
  formType.value = type
  resetForm()
  formLoading.value = true
  try {
    maxUnplannedNumber.value = number !== undefined ? Math.max(Number(number), 0) : undefined
    formData.value.deliveryDate = taskDeliveryDate || undefined
    if (productId) {
      formData.value.productId = productId
    }
    if (!id) {
      await loadProductProcessRoute(productId)
    }
    if (taskId) {
      formData.value.taskId = taskId
      taskDetailList.value = await TaskApi.getTaskDetailListByTaskId(formData.value.taskId)
      if (taskDetailId) {
        const taskDetails = taskDetailList.value.filter((item) => String(item.id) === String(taskDetailId))
        if (taskDetails?.[0]?.id) {
          formData.value.taskDetailId = taskDetails[0].id
          formData.value.finishDate = (taskDetails[0] as any).finishDate || undefined
          formData.value.deliveryDate = (taskDetails[0] as any).deliveryDate || taskDeliveryDate || undefined
        }
      }
    }
    if (number) {
      formData.value.planNumber = number
      formData.value.reyaNumber = number
    }
    if (!taskList.value.length) {
      taskList.value = await TaskApi.getPlanTaskList()
    }
    if (id) {
      const data = await PlanApi.getPlan(id)
      formData.value = {
        ...data,
        isCode: data.isCode ?? false,
        processRouteItems: normalizeProcessRouteItems((data as any).processRouteItems)
      }
    }
  } finally {
    formLoading.value = false
  }
}
defineExpose({ open })

const emit = defineEmits(['success'])
const submitForm = async () => {
  await formRef.value.validate()
  formLoading.value = true
  try {
    const data = {
      ...formData.value,
      processRouteItems: normalizeProcessRouteItems(formData.value.processRouteItems)
    } as unknown as PlanVO
    if (formType.value === 'create') {
      await PlanApi.createPlan(data)
      message.success(t('common.createSuccess'))
    } else {
      await PlanApi.updatePlan(data)
      message.success(t('common.updateSuccess'))
    }
    dialogVisible.value = false
    emit('success')
  } finally {
    formLoading.value = false
  }
}

const resetForm = () => {
  formData.value = {
    id: undefined,
    code: undefined,
    productId: undefined,
    taskDetailId: undefined,
    taskId: undefined,
    planNumber: 0,
    reyaNumber: undefined,
    finishNumber: 0,
    status: undefined,
    planStartTime: undefined,
    planEndTime: undefined,
    startTime: undefined,
    endTime: undefined,
    productionManagerId: undefined,
    remark: undefined,
    groupType: undefined,
    isEnable: undefined,
    isPreProduction: 0,
    isCode: true,
    latestStartTime: undefined,
    finishDate: undefined,
    deliveryDate: undefined,
    processRouteId: undefined,
    processRouteName: undefined,
    processRouteItems: []
  }
  maxUnplannedNumber.value = undefined
  formRef.value?.resetFields()
}

const handleTaskChange = async () => {
  taskDetailList.value = await TaskApi.getTaskDetailListByTaskId(formData.value.taskId)
  formData.value.taskDetailId = undefined
  formData.value.finishDate = undefined
  formRef.value?.validateField('planNumber')
}

const handleTaskDetailChange = async () => {
  syncFinishDateByTaskDetail()
  formRef.value?.validateField('planNumber')
}

const handlePlanStartTimeChange = () => {
  formRef.value?.validateField(['planStartTime', 'planEndTime'])
}

const handlePlanEndTimeChange = () => {
  formRef.value?.validateField(['planStartTime', 'planEndTime'])
}
</script>

<style scoped>
.process-route-items-table {
  width: 100%;
}
</style>
