<script lang="ts">
import type { ComponentPublicInstance } from 'vue'
import type { Dayjs } from 'dayjs'
import { debounce } from 'lodash-es'
import dayjs from 'dayjs'
import { computed, defineComponent, onMounted, ref, toRaw, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
  Button,
  Card,
  Checkbox,
  Col,
  Descriptions,
  Divider,
  Form,
  FormItem,
  Input,
  InputNumber,
  Modal,
  RangePicker,
  Row,
  Select,
  Space,
  Spin,
  Steps,
  Table,
  Tabs,
} from 'ant-design-vue'
import VueECharts from 'vue-echarts'
import { pointTableSchema, sampleInfoTableSchema } from './data'
import { BasicTable, useTable } from '@/components/Table'
import { PageWrapper } from '@/components/Page'
import {
  bottomModelApi,
  createDraftVersionApi,
  modelInfoApi,
  testModelApi,
  trainModelApi,
  updateModelInfo,
  versionListApi,
} from '@/api/alert/model/models'
import { fetchAssessReportList, fetchAssessReportNames } from '@/api/alert/model/assessReport'
import type { AssessReportSimple } from '@/api/alert/model/model/assessReportModel'
import { getExaHistorys } from '@/api/alert/exa/index'
import { useECharts } from '@/hooks/web/useECharts'
import { useMessage } from '@/hooks/web/useMessage'
import { useGo } from '@/hooks/web/usePage'
import Icon from '@/components/Icon'
import PointTransfer from '../components/PointTransfer.vue'
import { buildPointKeyFromInfo, parsePointKey } from '../components/pointTransferHelper'

export default defineComponent({
  components: {
    BasicTable,
    PageWrapper,
    [Divider.name]: Divider,
    [Card.name]: Card,
    [Descriptions.name]: Descriptions,
    [Descriptions.Item.name]: Descriptions.Item,
    [Steps.name]: Steps,
    [Steps.Step.name]: Steps.Step,
    ATabs: Tabs,
    ATabPane: Tabs.TabPane,
    ATable: Table,
    ARangePicker: RangePicker,
    AForm: Form,
    AFormItem: FormItem,
    VueECharts,
    AModal: Modal,
    AInput: Input,
    ACheckbox: Checkbox,
    AInputNumber: InputNumber,
    AButton: Button,
    ASpin: Spin,
    ARow: Row,
    ACol: Col,
    ASelect: Select,
    ASpace: Space,
    Icon,
    PointTransfer,
  },
  setup() {
    const { createMessage } = useMessage()
    const route = useRoute()
    const router = useRouter()
    const go = useGo()
    const id = route.params.id
    const routeVersion = computed(() => route.query.version as string | undefined)
    const model = ref(null)
    const brushActivated = ref<Set<number>>(new Set())
    const spinning = ref(false)
    let trainTimeCopy = ''
    const syncRouteVersion = (version: string) => {
      router.replace({ query: { ...route.query, version } })
    }
    const applyModelValue = (payload: any) => {
      if (!payload)
        return

      const normalized = normalizeTrainTime(payload)
      const previous = model.value || {}
      const merged: any = {
        ...previous,
        ...normalized,
      }

      if (!Array.isArray(normalized?.trainTime))
        merged.trainTime = previous?.trainTime ?? []
      if (!Array.isArray(normalized?.pointInfo))
        merged.pointInfo = previous?.pointInfo ?? []
      if (normalized?.para === undefined && previous?.para !== undefined)
        merged.para = previous.para

      model.value = merged
      trainTimeCopy = JSON.stringify(merged.trainTime || [])
    }

    const fetchModelInfo = async (version?: string) => {
      const path = version ? `${id}?version=${encodeURIComponent(version)}` : (routeVersion.value ? `${id}?version=${encodeURIComponent(routeVersion.value)}` : id)
      const modelInfo = await modelInfoApi(path)
      applyModelValue(modelInfo)
      selectedVersion.value = modelInfo?.version || modelInfo?.Cur_Version || ''
      if (selectedVersion.value)
        syncRouteVersion(selectedVersion.value)
      await loadReportName(selectedVersion.value)
      getHistory()
    }

    const pointData = computed(() => {
      const list = model.value?.pointInfo || []
      return list.map((p: any) => ({
        description: p.description ?? p.Description,
        pointId: p.pointId ?? p.PointId,
        unit: p.unit ?? p.Unit,
        Upper: p.Upper ?? p.upper,
        Lower: p.Lower ?? p.lower,
        dead: p.dead === true ? '是' : '否',
        limit: p.limit === true ? '是' : '否',
        upperBound: p.upperBound ?? p.upperbound ?? p.upperBound,
        lowerBound: p.lowerBound ?? p.lowerbound ?? p.lowerBound,
        TMax: p.TMax ?? p.tMax,
        TMin: p.TMin ?? p.tMin,
        TAvg: p.TAvg ?? p.tAvg,
        DMax: p.DMax ?? p.dMax,
        DMin: p.DMin ?? p.dMin,
        DAvg: p.DAvg ?? p.dAvg,
      }))
    })
    const [pointTable] = useTable({
      columns: pointTableSchema,
      pagination: true,
      dataSource: pointData,
      scroll: { y: 300 },
    })

    const trainTime = computed(() => model.value?.trainTime || [])
    const [trainTimeTable] = useTable({
      columns: sampleInfoTableSchema,
      dataSource: trainTime,
      scroll: { y: 300 },
    })

    const updatePrincipalFromTrainTime = (trainTimeList: any[]) => {
      if (!Array.isArray(trainTimeList) || !model.value)
        return
      // principal is the sum of mode for each trainTime entry
      model.value.principal = trainTimeList.reduce((sum, item) => {
        const modeVal = Number(item?.mode)
        return sum + (Number.isFinite(modeVal) ? modeVal : 0)
      }, 0)
    }

    watch(
      () => model.value?.trainTime,
      newTrainTime => updatePrincipalFromTrainTime(newTrainTime as any[]),
      { deep: true, immediate: true },
    )

    const activeKey = ref('1')
    type RangeValue = [Dayjs, Dayjs]
    const currentDate: Dayjs = dayjs('2023-10-29 00:00:00')
    const lastMonthDate: Dayjs = dayjs('2023-10-28 16:00:00')
    const rangeValue: RangeValue = [
      lastMonthDate,
      currentDate,
    ]
    const historyTime = ref<RangeValue>(rangeValue)
    const historyList = ref<any[]>([])
    const echartsRefs = ref<any[]>([])

    async function getHistory() {
      if (!historyTime.value)
        return
      spinning.value = true
      if (model.value.para) {
        await getTestData()
      }
      else {
        const params = {
          startTime: historyTime.value[0].format('YYYY-MM-DD HH:mm:ss'),
          endTime: historyTime.value[1].format('YYYY-MM-DD HH:mm:ss'),
          itemName: model.value?.pointInfo
            .map(item => item.pointId)
            .join(','),
          interval: model.value.sampling,
        }
        const history = await getExaHistorys(params)
        historyList.value = history.map((item, index) => {
          const point = model.value?.pointInfo[index]
          return {
            data: [item],
            name: `${index + 1}.${point?.description}(${point?.pointId})`,
          }
        })
        echartsRefs.value = Array.from({ length: historyList.value.length })
        brushActivated.value = new Set()
      }

      spinning.value = false
    }

    async function getTestData(range?: RangeValue) {
      const timeRange = range || historyTime.value
      if (!timeRange)
        return
      const params = {
        Model_id: id,
        version: model.value?.version ? model.value?.version : 'v-test',
        Test_Data: {
          time: timeRange
            .map(t => dayjs(t).format('YYYY-MM-DD HH:mm:ss'))
            .join(','),
          points: model.value.pointInfo.map(t => t.pointId).join(','),
          interval: model.value.sampling * 1000,
        },
      }
      const result = await testModelApi(params)
      const sampleData = result?.sampleData ?? result?.SampleData ?? []
      const reconData = result?.reconData ?? result?.ReconData ?? []
      if (!Array.isArray(sampleData) || !Array.isArray(reconData) || sampleData.length === 0 || reconData.length === 0) {
        historyList.value = []
        createMessage.warning('未获取到测试数据')
        return
      }
      const xData = generateTimeList(
        timeRange,
        model.value.sampling * 1000,
      )
      historyList.value = sampleData.map((item, index) => {
        const point = model.value?.pointInfo[index]
        return {
          data: [
            (Array.isArray(item) ? item : []).map((t, i) => {
              return [xData[i], t]
            }),
            (Array.isArray(reconData[index]) ? reconData[index] : []).map((t, i) => {
              return [xData[i], t]
            }),
          ],
          name: `${index + 1}.${point?.description}(${point?.pointId})`,
        }
      })
      brushActivated.value = new Set()
    }

    function generateTimeList(time: RangeValue, intervalMs: number) {
      const [t1, t2] = time
      const count = Math.floor(t2.diff(t1, 'millisecond') / intervalMs) + 1
      return Array.from({ length: count }, (_, i) => t1.add(i * intervalMs, 'millisecond').valueOf())
    }

    function normalizeTrainTime(modelInfo: any) {
      if (!modelInfo?.trainTime || !Array.isArray(modelInfo.trainTime))
        return modelInfo
      const samplingMs = (modelInfo.sampling || 0) * 1000
      modelInfo.trainTime = modelInfo.trainTime.map((item: any) => {
        const durationSec = item.duration || Math.max(0, (dayjs(item.et).valueOf() - dayjs(item.st).valueOf()) / 1000)
        const number = item.number !== undefined && item.number !== '' ? item.number : (samplingMs > 0 ? Math.floor((durationSec * 1000) / samplingMs) : '')
        const filter = item.filter !== undefined && item.filter !== '' ? item.filter : 0
        const mode = item.mode !== undefined && item.mode !== '' ? item.mode : (number !== '' ? Math.max(0, number - filter) : '')
        return {
          ...item,
          duration: durationSec,
          number,
          filter,
          mode,
        }
      })
      return modelInfo
    }

    function getOption(item: any) {
      const name = ['测量值', '模型值', '']
      const color = ['blue', '#ff6f00', 'red']
      const yIndex = [0, 0, 1]
      const option = {
        xAxis: {
          type: 'time',
          axisLabel: {
            formatter(value) {
              const date = new Date(value)
              return date.toLocaleString()
            },
          },
        },
        yAxis: [{ type: 'value' }, { type: 'value', max: 10, show: false }],
        series: item.data.map((item, index) => {
          return {
            data: item,
            type: 'line',
            smooth: true,
            symbol: 'none',
            name: name[index],
            color: color[index],
            yAxisIndex: yIndex[index],
          }
        }),
        legend: {},
        dataZoom: [{}],
        brush: {
          toolbox: ['lineX'],
          xAxisIndex: 0,
          brushType: 'lineX',
        },
        grid: [
          {
            left: 60,
            right: 50,
            bottom: 50,
            top: 30,
          },
        ],
      }
      return option
    }

    function setChartRef(
      el: Element | ComponentPublicInstance | null,
      index: number,
    ) {
      let dom: HTMLElement | null = null
      if (el) {
        if ('$el' in el && (el as any).$el instanceof HTMLElement)
          dom = (el as any).$el
        else if (el instanceof HTMLElement)
          dom = el
      }
      if (dom)
        useECharts(ref(dom as HTMLDivElement))
    }

    function setEchartsRef(el: any, index: number) {
      if (el)
        echartsRefs.value[index] = el
    }
    const isInitBrush = ref(true)
    function onChartFinished(index: number) {
      if (brushActivated.value.has(index))
        return
      const chart = echartsRefs.value[index]
      if (!chart)
        return
      chart.dispatchAction({
        type: 'takeGlobalCursor',
        key: 'brush',
        brushOption: {
          brushType: 'lineX',
          brushMode: 'multiple',
        },
      })
      const areas = (model.value?.trainTime || []).map(row => ({
        brushType: 'lineX',
        xAxisIndex: 0,
        coordRange: [
          dayjs(row.st).format('YYYY-MM-DD HH:mm:ss'),
          dayjs(row.et).format('YYYY-MM-DD HH:mm:ss'),
        ],
      }))
      chart.dispatchAction({
        type: 'brush',
        areas,
      })
      isInitBrush.value = true
      brushActivated.value.add(index)
    }

    onMounted(async () => {
      await fetchModelInfo()
    })
    const onBrushSelected = debounce((params) => {
      if (isInitBrush.value) {
        isInitBrush.value = false
        return
      }
      if (!isInitBrush.value && model.value?.version != 'v-test')
        return

      const selected = params.batch[0].selected
      if (selected.length > 0) {
        const areas = mergeAreas(params.batch[0].areas).map(area => ({
          brushType: area.brushType,
          xAxisIndex: 0,
          coordRange: area.coordRange,
        }))
        const trainTime = areas.map((area) => {
          const [stRaw, etRaw] = area.coordRange
          const st = typeof stRaw === 'string' ? dayjs(stRaw).valueOf() : stRaw
          const et = typeof etRaw === 'string' ? dayjs(etRaw).valueOf() : etRaw
          console.log('Selected area:', { st, et }, area)
          return {
            st: dayjs(st).format('YYYY-MM-DD HH:mm:ss'),
            et: dayjs(et).format('YYYY-MM-DD HH:mm:ss'),
            duration: Math.round((et - st) / 1000),
            number: '', // 采样数量（如有数据可补充）
            filter: '', // 清洗样本数（如有数据可补充）
            mode: '', // 有效样本数（如有数据可补充）
          }
        })
        console.log('Selected train time:', trainTime)
        if (trainTimeCopy === JSON.stringify(trainTime))
          return
        model.value.trainTime = trainTime
        trainTimeCopy = JSON.stringify(trainTime)
        echartsRefs.value.forEach((chart, index) => {
          if (chart) {
            chart.dispatchAction({
              type: 'brush',
              areas,
            })
            isInitBrush.value = true
          }
        })
        updateModelInfoDebounced()
      }
    }, 300)

    function mergeAreas(areas: any[]) {
      if (!areas.length)
        return []
      // 只合并 brushType 和 xAxisIndex 相同的区间
      const sorted = [...areas].sort(
        (a, b) => a.coordRange[0] - b.coordRange[0],
      )
      const merged: any[] = []
      for (const area of sorted) {
        if (
          merged.length
          && merged[merged.length - 1].brushType === area.brushType
          && merged[merged.length - 1].xAxisIndex === area.xAxisIndex
          && merged[merged.length - 1].coordRange[1] >= area.coordRange[0]
        ) {
          // 有交集或相邻，合并
          merged[merged.length - 1].coordRange[1] = Math.max(
            merged[merged.length - 1].coordRange[1],
            area.coordRange[1],
          )
        }
        else {
          // 新区间
          merged.push({
            brushType: area.brushType,
            xAxisIndex: area.xAxisIndex,
            coordRange: [...area.coordRange],
          })
        }
      }
      return merged
    }

    // 防抖更新
    const updateModelInfoDebounced = debounce(() => {
      const val = toRaw(model.value)
      if (val && val.id)
        updateModelInfo(val)
    }, 500)

    function handleDeleteTrainTime(index: number) {
      if (!canEditModel.value) {
        createMessage.warning('非草稿版本不可修改训练时间')
        return
      }
      if (!model.value?.trainTime)
        return
      // 赋值新数组，确保响应式
      model.value.trainTime = [
        ...model.value.trainTime.slice(0, index),
        ...model.value.trainTime.slice(index + 1),
      ]
      // 删除后同步更新所有图表的 brush 区域
      const areas = (model.value.trainTime || []).map(row => ({
        brushType: 'lineX',
        xAxisIndex: 0,
        coordRange: [dayjs(row.st).valueOf(), dayjs(row.et).valueOf()],
      }))
      echartsRefs.value.forEach((chart) => {
        if (chart) {
          chart.dispatchAction({
            type: 'brush',
            areas,
          })
          isInitBrush.value = true
        }
      })
      updateModelInfoDebounced()
    }
    async function clearModel() {
      if (!canEditModel.value) {
        createMessage.warning('非草稿版本不可清除训练结果')
        return
      }
      model.value.para = null
      updateModelInfoDebounced()
      await getHistory()
    }

    async function trainModel() {
      if (!canEditModel.value) {
        createMessage.warning('非草稿版本不可训练模型')
        return
      }
      const modelInfo = model.value
      if (!modelInfo || !modelInfo.id) {
        console.error('模型信息不完整，无法训练')
        return
      }
      const pointInfo = modelInfo.pointInfo || []
      if (pointInfo.length === 0) {
        console.error('模型参数点信息为空，无法训练')
        return
      }
      const params = {
        conditon: modelInfo.alarmmodelset?.alarmcondition || '1=1',
        Hyper_para: {
          percent: modelInfo.rate,
        },
        Train_Data: {
          points: pointInfo.map(item => item.pointId).join(','),
          dead: pointInfo.map(item => (item.dead ? '1' : '0')).join(','),
          limit: pointInfo.map(item => (item.limit ? '1' : '0')).join(','),
          uplow: pointInfo
            .map(
              item =>
                `${item.Upper ? item.Upper : null},${
                  item.Lower ? item.Lower : null
                }`,
            )
            .join(';'),
          interval: modelInfo.sampling * 1000,
          time: modelInfo.trainTime
            .map(item => `${item.st},${item.et}`)
            .join(';'),
        },
        type: 'PCA',
        smote_config: [],
        smote: true,
      }
      spinning.value = true
      try {
        const response = await trainModelApi(params)
        model.value.para = response

        const modelInfoDetail = response.Model_info || response.modelInfo
        if (modelInfoDetail) {
          model.value.principal = modelInfoDetail.K ?? modelInfoDetail.k ?? model.value.principal
          model.value.precision = modelInfoDetail.R ? `${(modelInfoDetail.R * 100).toFixed(2)}%` : model.value.precision

          const pxMax = modelInfoDetail.Train_X_max || modelInfoDetail.trainXMax || []
          const pxMin = modelInfoDetail.Train_X_min || modelInfoDetail.trainXMin || []
          const pxMean = modelInfoDetail.Train_X_mean || modelInfoDetail.trainXMean || []
          const pbMax = (modelInfoDetail.Train_X_bais_max || modelInfoDetail.trainXBaisMax || [])[0] || []
          const pbMin = (modelInfoDetail.Train_X_bais_min || modelInfoDetail.trainXBaisMin || [])[0] || []
          const pbMean = (modelInfoDetail.Train_X_bais_mean || modelInfoDetail.trainXBaisMean || [])[0] || []
          const qcul99Line = modelInfoDetail.QCUL_99_line || modelInfoDetail.qcul99Line || []

          model.value.pointInfo = (model.value.pointInfo || []).map((p: any, idx: number) => {
            const q99 = qcul99Line[idx]
            const upperB = Number.parseFloat(p.upperBound)
            const lowerB = Number.parseFloat(p.lowerBound)
            return {
              ...p,
              TMax: pxMax[idx] !== undefined ? Number(pxMax[idx]).toFixed(2) : p.TMax,
              TMin: pxMin[idx] !== undefined ? Number(pxMin[idx]).toFixed(2) : p.TMin,
              TAvg: pxMean[idx] !== undefined ? Number(pxMean[idx]).toFixed(2) : p.TAvg,
              DMax: pbMax[idx] !== undefined ? Number(pbMax[idx]).toFixed(2) : p.DMax,
              DMin: pbMin[idx] !== undefined ? Number(pbMin[idx]).toFixed(2) : p.DMin,
              DAvg: pbMean[idx] !== undefined ? Number(pbMean[idx]).toFixed(2) : p.DAvg,
              upperBound:
                Number.isNaN(upperB) || upperB === undefined
                  ? (q99 !== undefined ? Number(q99).toFixed(2) : p.upperBound)
                  : p.upperBound,
              lowerBound:
                Number.isNaN(lowerB) || lowerB === undefined
                  ? (q99 !== undefined ? (-Number(q99)).toFixed(2) : p.lowerBound)
                  : p.lowerBound,
            }
          })
        }

        // 填充训练区间的采样/清洗/有效样本数，如果接口有总数则均摊，否则保留原值
        if (Array.isArray(model.value.trainTime) && model.value.trainTime.length) {
          const beforeTotal = response.BeforeCleanSamNum ?? response.beforeCleanSamNum
          const afterTotal = response.AfterCleanSamNum ?? response.afterCleanSamNum
          if (beforeTotal !== undefined && afterTotal !== undefined) {
            const avgBefore = Math.floor(beforeTotal / model.value.trainTime.length)
            const avgAfter = Math.floor(afterTotal / model.value.trainTime.length)
            model.value.trainTime = model.value.trainTime.map((t: any) => ({
              ...t,
              number: t.number || avgBefore,
              filter: t.filter || Math.max(0, avgBefore - avgAfter),
              mode: t.mode || avgAfter,
            }))
          }
        }

        updateModelInfoDebounced()
        await updateModelInfoDebounced.flush()
        // 训练完成后自动触发测试，优先使用训练时间范围
        try {
          if (model.value.trainTime && model.value.trainTime.length > 0) {
            const sorted = [...model.value.trainTime].sort(
              (a, b) => dayjs(a.st).valueOf() - dayjs(b.st).valueOf(),
            )
            const trainRange: RangeValue = [
              dayjs(sorted[0].st),
              dayjs(sorted[sorted.length - 1].et),
            ]
            await getTestData(trainRange)
          }
          else {
            await getTestData()
          }
        }
        catch (e) {
          console.error('自动测试失败:', e)
        }
        createMessage.success('模型训练成功')
      }
      catch (error) {
        console.error('模型训练失败:', error)
        createMessage.error('模型训练失败')
      }

      spinning.value = false
    }
    const editForm = ref({
      index: -1,
      Upper: '',
      Lower: '',
      lowerBound: '',
      upperBound: '',
      dead: true,
      limit: false,
    })
    const openEditPointModal = ref<boolean>(false)
    let pointEditRecord = null
    function editPoint() {
      // 这里可以添加编辑点的逻辑
      model.value.pointInfo[editForm.value.index] = {
        ...model.value.pointInfo[editForm.value.index],
        Upper: editForm.value.Upper,
        Lower: editForm.value.Lower,
        lowerBound: editForm.value.lowerBound,
        upperBound: editForm.value.upperBound,
        dead: editForm.value.dead,
        limit: editForm.value.limit,
      }
      updateModelInfoDebounced()
      pointEditRecord.Upper = editForm.value.Upper
      pointEditRecord.Lower = editForm.value.Lower
      pointEditRecord.lowerBound = editForm.value.lowerBound
      pointEditRecord.upperBound = editForm.value.upperBound
      pointEditRecord.dead = editForm.value.dead
      pointEditRecord.limit = editForm.value.limit
      openEditPointModal.value = false
    }

    function openPointModal(index, record) {
      if (!canEditModel.value) {
        createMessage.warning('非草稿版本不可编辑测点参数')
        return
      }
      // 当前页 index
      const pageIndex = index
      // 全局 index
      const globalIndex = model.value.pointInfo.findIndex(
        item => item.pointId === record.pointId,
      )
      openEditPointModal.value = true
      pointEditRecord = record
      const normalizeBool = (val: any) => {
        if (val === true || val === '是' || val === 1 || val === '1')
          return true
        if (val === false || val === '否' || val === 0 || val === '0')
          return false
        return !!val
      }
      editForm.value = {
        index: globalIndex,
        Upper: record?.Upper ?? '',
        Lower: record?.Lower ?? '',
        lowerBound: record?.lowerBound ?? '',
        upperBound: record?.upperBound ?? '',
        dead: normalizeBool(record?.dead),
        limit: normalizeBool(record?.limit),
      }
    }

    const mode = ref({
      alarmcondition: '1=1',
      alarmname: '全工况运行',
    })
    const openEditModeModal = ref<boolean>(false)
    const normalizeVersion = (val?: string | null) => (val ? String(val).trim().toLowerCase() : '')

    function openEditMode() {
      if (!canEditModel.value) {
        createMessage.warning('非草稿版本不可修改模式')
        return
      }
      openEditModeModal.value = true
      mode.value = {
        alarmcondition: model.value?.alarmmodelset?.alarmcondition || '1=1',
        alarmname: model.value?.alarmmodelset?.alarmname || '全工况运行',
      }
    }
    function closeEditMode() {
      openEditModeModal.value = false
    }
    function handleEditMode() {
      // 这里可以添加编辑模式的逻辑
      model.value.alarmmodelset = mode.value
      updateModelInfoDebounced()
      closeEditMode()
    }

    const openEditModelModal = ref(false)
    const editModelForm = ref({
      sampling: 0,
      rate: 0,
      selectedKeys: [],
    })

    function openEditModel() {
      if (!canEditModel.value) {
        createMessage.warning('非草稿版本不可修改模型')
        return
      }
      editModelForm.value.sampling = model.value?.sampling || 0
      editModelForm.value.rate = model.value?.rate || 0
      editModelForm.value.selectedKeys = (model.value?.pointInfo || []).map(item => buildPointKeyFromInfo({
        description: item.description ?? item.Description,
        pointId: item.pointId ?? item.PointId,
        unit: item.unit ?? item.Unit,
        Lower: item.Lower ?? item.lower,
        Upper: item.Upper ?? item.upper,
      }))
      openEditModelModal.value = true
    }
    function handleEditModelOk() {
      if (!canEditModel.value) {
        createMessage.warning('非草稿版本不可修改模型')
        return
      }
      model.value.sampling = editModelForm.value.sampling
      model.value.rate = editModelForm.value.rate
      model.value.pointInfo = editModelForm.value.selectedKeys.map((key) => {
        const { description, pointId, unit, Lower, Upper } = parsePointKey(key)
        return {
          description,
          pointId,
          unit,
          Lower,
          Upper,
          dead: true,
          limit: false,
        }
      })
      clearModel()
      openEditModelModal.value = false
    }
    function handleEditModelCancel() {
      openEditModelModal.value = false
    }

    const reportModalVisible = ref(false)
    const reportLoading = ref(false)
    const reportList = ref<AssessReportSimple[]>([])
    const selectedReportId = ref<number | null>(null)
    const reportName = ref<string>('暂无报告')
    const reportNameOptions = ref<{ label: string, value: number }[]>([])
    const reportNameSelectVisible = ref(false)
    const selectedReportNameId = ref<number | null>(null)
    const isVTestVersion = computed(() => {
      const version = normalizeVersion(model.value?.Cur_Version || model.value?.version)
      return version === '' || version === 'v-test'
    })
    const canEditModel = computed(() => {
      const version = normalizeVersion(selectedVersion.value || model.value?.Cur_Version || model.value?.version)
      return version === '' || version === 'v-test'
    })
    const isBottomed = computed(() => model.value?.btmState === '已下装')
    const reportColumns = [
      { title: '评估时间', dataIndex: 'assessTime' },
      { title: '得分', dataIndex: 'score' },
      { title: '覆盖面', dataIndex: 'coverRange' },
      { title: '验证人', dataIndex: 'identifier' },
      { title: '版本', dataIndex: 'version' },
      { title: '模式', dataIndex: 'conditionName' },
    ]

    function onSelectReport(selectedRowKeys: (string | number)[]) {
      selectedReportId.value = (selectedRowKeys && selectedRowKeys.length > 0)
        ? Number(selectedRowKeys[0])
        : null
    }

    function openReportSelector() {
      loadReportName()
      reportNameSelectVisible.value = true
    }

    function confirmReportSelect() {
      if (selectedReportNameId.value)
        goAssessReport(selectedReportNameId.value)
      else
        goAssessReport()

      reportNameSelectVisible.value = false
    }

    async function openBottomModal() {
      if (!model.value?.para) {
        createMessage.error('模型未训练，无法下装')
        return
      }
      if (!model.value?.trainTime || model.value.trainTime.length === 0) {
        createMessage.error('模型尚未建立，无法下装')
        return
      }
      if (model.value?.btmState === '已下装' && (model.value?.Cur_Version || model.value?.version) !== 'v-test') {
        createMessage.error('模型已下装，无法重复操作')
        return
      }
      reportLoading.value = true
      try {
        const version = model.value?.Cur_Version || model.value?.version || 'v-test'
        // todo valid需要改回true，现在为了能下装测试先改成false
        const list = await fetchAssessReportList({ modelId: id as string, version, valid: false })
        reportList.value = list || []
        if (!reportList.value.length) {
          createMessage.error('请先完成合格并审核通过的评估报告')
          return
        }
        selectedReportId.value = reportList.value[0]?.id ?? null
        reportModalVisible.value = true
      }
      catch (error) {
        console.error('获取评估报告失败:', error)
        createMessage.error('获取评估报告失败')
      }
      finally {
        reportLoading.value = false
      }
    }

    async function loadReportName(version?: string) {
      try {
        reportLoading.value = true
        const names = await fetchAssessReportNames({ modelId: id as string, version: version || selectedVersion.value })
        if (names && names.length > 0) {
          reportName.value = names[0].name
          selectedReportId.value = names[0].id
          selectedReportNameId.value = names[0].id
          reportNameOptions.value = names.map(n => ({ label: n.name, value: n.id }))
        }
        else {
          reportName.value = '暂无报告'
          selectedReportId.value = null
          selectedReportNameId.value = null
          reportNameOptions.value = []
        }
      }
      catch (error) {
        reportName.value = '暂无报告'
        selectedReportNameId.value = null
        reportNameOptions.value = []
      }
      finally {
        reportLoading.value = false
      }
    }

    async function confirmBottomModel() {
      if (!selectedReportId.value) {
        createMessage.warning('请选择评估报告')
        return
      }
      spinning.value = true
      try {
        const response = await bottomModelApi(model.value.id, selectedReportId.value)
        const bottomedVersion = response?.Cur_Version || response?.version
        if (bottomedVersion) {
          selectedVersion.value = bottomedVersion
          syncRouteVersion(bottomedVersion)
        }
        await fetchModelInfo(bottomedVersion)
        console.log('模型下装成功:', model.value)
        createMessage.success('模型下装成功')
        reportModalVisible.value = false
      }
      catch (error) {
        console.error('模型下装失败:', error)
        createMessage.error('模型下装失败')
      }
      finally {
        spinning.value = false
      }
    }

    const versionLoading = ref(false)
    const versionList = ref<any[]>([])
    const selectedVersion = ref<string>('')
    const versionOptions = computed(() => {
      const options = versionList.value
        .filter(v => v?.version)
        .map(v => ({ label: v.version, value: v.version }))
      if (selectedVersion.value && !options.find(o => o.value === selectedVersion.value))
        options.unshift({ label: selectedVersion.value, value: selectedVersion.value })

      return options
    })
    const versionDropdownVisible = ref(false)

    async function loadVersionList() {
      versionLoading.value = true
      try {
        const list = await versionListApi(id)
        versionList.value = list || []
      }
      catch (error) {
        createMessage.error('获取版本列表失败')
      }
      finally {
        versionLoading.value = false
      }
    }

    async function handleVersionChange(value: string) {
      if (!value)
        return
      await fetchModelInfo(value)
      syncRouteVersion(value)
    }

    async function createDraftVersion() {
      const confirmed = await new Promise<boolean>((resolve) => {
        Modal.confirm({
          title: '确认创建新版本？',
          content: '创建新版本后可重新训练、评估和下装。',
          onOk: () => resolve(true),
          onCancel: () => resolve(false),
        })
      })
      if (!confirmed)
        return

      try {
        await createDraftVersionApi(id)
        selectedVersion.value = 'v-test'
        if (model.value) {
          model.value = {
            ...model.value,
            Cur_Version: 'v-test',
            version: 'v-test',
          }
        }
        syncRouteVersion('v-test')
        createMessage.success('已创建草稿版本 v-test，请重新训练')
        versionList.value = []
        await fetchModelInfo('v-test')
      }
      catch (error) {
        createMessage.error('创建草稿版本失败')
      }
    }
    const showTrainActions = computed(() => canEditModel.value)

    function goAssessReport(reportId?: number | null | Event) {
      // 防止直接作为事件处理时收到 PointerEvent
      const rid = (reportId && typeof reportId === 'object') ? null : reportId
      const version = selectedVersion.value || model.value?.Cur_Version || 'v-test'
      const algorithm = model.value?.algorithm || 'PCA'
      const extra = rid ? `&reportId=${rid}` : ''
      go(`/model/assess-report/${id}?version=${encodeURIComponent(version)}&algorithm=${algorithm}${extra}`)
    }

    return {
      normalizeVersion,
      pointTable,
      model,
      selectedVersion,
      versionOptions,
      versionDropdownVisible,
      reportName,
      activeKey,
      historyTime,
      historyList,
      getHistory,
      getOption,
      setChartRef,
      setEchartsRef,
      onChartFinished,
      echartsRefs,
      onBrushSelected,
      trainTimeTable,
      handleDeleteTrainTime,
      openEditPointModal,
      editPoint,
      openPointModal,
      editForm,
      trainModel,
      openEditModeModal,
      openEditMode,
      closeEditMode,
      handleEditMode,
      mode,
      spinning,
      clearModel,
      openEditModelModal,
      editModelForm,
      openEditModel,
      handleEditModelOk,
      handleEditModelCancel,
      openBottomModal,
      confirmBottomModel,
      reportModalVisible,
      reportList,
      reportColumns,
      reportLoading,
      selectedReportId,
      onSelectReport,
      reportName,
      reportNameOptions,
      reportNameSelectVisible,
      selectedReportNameId,
      openReportSelector,
      confirmReportSelect,
      loadReportName,
      versionList,
      versionLoading,
      loadVersionList,
      handleVersionChange,
      createDraftVersion,
      goAssessReport,
      showTrainActions,
      canEditModel,
    }
  },
})
</script>

<template>
  <PageWrapper content-background>
    <div>
      <a-card title="模型信息" :bordered="false">
        <a-descriptions size="small" :column="4" bordered>
          <a-descriptions-item label="模型名称">
            {{ model?.name }}
          </a-descriptions-item>
          <a-descriptions-item label="描述">
            {{ model?.description || "暂无描述" }}
          </a-descriptions-item>
          <a-descriptions-item label="版本">
            <template v-if="!versionDropdownVisible">
              <span
                style=" text-decoration: underline;cursor: pointer"
                @click="() => { versionDropdownVisible = true; loadVersionList() }"
              >
                {{ selectedVersion || 'v-test' }}
              </span>
              <a-button type="link" size="small" @click="createDraftVersion">
                <Icon icon="ant-design:plus-circle-outlined" />
              </a-button>
            </template>
            <template v-else>
              <a-select
                v-model:value="selectedVersion"
                size="small"
                style="min-width: 160px"
                :loading="versionLoading"
                :options="versionOptions"
                placeholder="选择版本"
                :allow-clear="false"
                @change="(v) => { handleVersionChange(v); versionDropdownVisible = false }"
                @blur="versionDropdownVisible = false"
              />
            </template>
          </a-descriptions-item>
          <a-descriptions-item label="评估报告">
            <span
              style=" text-decoration: underline;cursor: pointer"
              @click="openReportSelector"
            >
              {{ reportName }}
            </span>
            <a-button type="link" size="small" @click="goAssessReport">
              <Icon icon="ant-design:plus-circle-outlined" />
            </a-button>
          </a-descriptions-item>
          <a-descriptions-item label="创建人">
            {{ model?.founder }}
          </a-descriptions-item>
          <a-descriptions-item label="创建时间">
            {{ model?.creatTime || model?.createTime }}
          </a-descriptions-item>
          <a-descriptions-item label="最近修改人">
            {{ model?.Modifier || "暂无" }}
          </a-descriptions-item>
          <a-descriptions-item label="最近修改时间">
            {{ model?.modifiedTime || "暂无" }}
          </a-descriptions-item>
        </a-descriptions>
        <a-divider />
        <a-descriptions size="small" :column="4" bordered>
          <a-descriptions-item label="算法">
            {{ model?.algorithm || "PCA" }}
          </a-descriptions-item>
          <a-descriptions-item label="训练采样间隔">
            {{ model?.sampling }}
          </a-descriptions-item>
          <a-descriptions-item label="参数个数">
            {{ model?.pointInfo.length || "暂无" }}
          </a-descriptions-item>
          <a-descriptions-item label="最小主元贡献率">
            {{ model?.rate }}
          </a-descriptions-item>
          <a-descriptions-item label="最小主元个数">
            {{ model?.principal }}
          </a-descriptions-item>
          <a-descriptions-item label="模型性能">
            {{ model?.precision }}
          </a-descriptions-item>
          <a-descriptions-item label="训练总时长(h)">
            {{
              (
                model?.trainTime.reduce(
                  (total, item) => total + item.duration,
                  0,
                ) / 3600
              ).toFixed(2) || "暂无"
            }}
          </a-descriptions-item>
          <a-descriptions-item label="有效样本数">
            {{ model?.principal }}
          </a-descriptions-item>
        </a-descriptions>
      </a-card>
      <a-card
        title="模式"
        :bordered="false"
        style="margin-top: 16px; margin-bottom: -20px"
      >
        <a-button size="large" :disabled="!canEditModel" @click="openEditMode">
          {{ model?.alarmmodelset?.alarmname || '全工况运行' }}
        </a-button>
      </a-card>

      <a-card :bordered="false">
        <a-tabs v-model:active-key="activeKey">
          <a-tab-pane key="1" tab="训练采样时间">
            <BasicTable @register="trainTimeTable">
              <template #action="{ record, index }">
                <a-button
                  v-if="showTrainActions"
                  type="link"
                  danger
                  @click="handleDeleteTrainTime(index)"
                >
                  删除
                </a-button>
                <span v-else>--</span>
              </template>
            </BasicTable>
          </a-tab-pane>
          <a-tab-pane key="2" tab="测点参数">
            <BasicTable @register="pointTable">
              <template #action="{ record, index }">
                <a-button
                  v-if="showTrainActions"
                  type="primary"
                  @click="openPointModal(index, record)"
                >
                  编辑
                </a-button>
                <span v-else>--</span>
              </template>
            </BasicTable>
          </a-tab-pane>
        </a-tabs>
      </a-card>

      <a-card title="智能训练" :bordered="false">
        <div style="display: flex; align-items: center">
          <a-form layout="inline" style="flex: 1">
            <a-form-item label="模型预览时间范围">
              <a-range-picker
                v-model:value="historyTime"
                show-time
                @change="getHistory"
              />
            </a-form-item>
          </a-form>
          <a-button
            v-if="showTrainActions"
            type="primary"
            style="margin-left: auto"
            @click="trainModel"
          >
            模型训练
          </a-button>
          <a-button
            v-if="showTrainActions"
            type="primary"
            style="margin-left: 10px"
            @click="clearModel"
          >
            清除训练结果
          </a-button>
          <a-button
            v-if="showTrainActions"
            type="primary"
            style="margin-left: 6px"
            @click="openEditModel"
          >
            修改模型
          </a-button>
          <a-button
            v-if="showTrainActions"
            danger
            style="margin-left: 10px"
            @click="openBottomModal"
          >
            下装
          </a-button>
        </div>
        <a-divider />
        <a-spin :spinning="spinning" size="large">
          <div
            v-for="(item, index) in historyList"
            :key="index"
            class="echart-box"
            style="width: 100%"
          >
            <a-card :bordered="false" style="margin-bottom: 16px">
              <template #title>
                <span style="font-size: 20px">{{ item.name }}</span>
              </template>
              <VueECharts
                :ref="(el) => setEchartsRef(el, index)"
                :option="getOption(item)"
                autoresize
                style="width: 100%; height: 200px"
                @finished="() => onChartFinished(index)"
                @brush-selected="onBrushSelected"
              />
            </a-card>
          </div>
        </a-spin>
      </a-card>
    </div>
    <a-modal
      v-model:open="reportModalVisible"
      title="选择评估报告"
      :confirm-loading="spinning"
      @ok="confirmBottomModel"
    >
      <a-table
        :columns="reportColumns"
        :data-source="reportList"
        :loading="reportLoading"
        row-key="id"
        :pagination="false"
        size="small"
        :row-selection="{
          type: 'radio',
          selectedRowKeys: selectedReportId ? [selectedReportId] : [],
          onChange: onSelectReport,
        }"
      />
    </a-modal>
    <a-modal
      v-model:open="reportNameSelectVisible"
      title="评估报告版本"
      @ok="confirmReportSelect"
      @cancel="() => { reportNameSelectVisible = false }"
    >
      <a-select
        v-model:value="selectedReportNameId"
        :options="reportNameOptions"
        style="width: 100%"
        placeholder="请选择评估报告"
        :loading="reportLoading"
      />
    </a-modal>
    <a-modal
      v-model:open="openEditPointModal"
      title="更改上下限"
      @ok="editPoint"
    >
      <a-form
        :model="editForm"
        :label-col="{ span: 7 }"
        :wrapper-col="{ span: 15 }"
      >
        <a-form-item label="上限">
          <a-input-number
            v-model:value="editForm.Upper"
            placeholder="请输入上限"
          />
        </a-form-item>
        <a-form-item label="下限">
          <a-input-number
            v-model:value="editForm.Lower"
            placeholder="请输入下限"
          />
        </a-form-item>
        <a-form-item label="残差上限">
          <a-input-number
            v-model:value="editForm.upperBound"
            placeholder="请输入残差上限"
          />
        </a-form-item>
        <a-form-item label="残差下限">
          <a-input-number
            v-model:value="editForm.lowerBound"
            placeholder="请输入残差下限"
          />
        </a-form-item>
        <a-form-item label="清洗方式" style="margin-top: 16px">
          <a-checkbox v-model:checked="editForm.dead">
            死区清洗
          </a-checkbox>
          <a-checkbox v-model:checked="editForm.limit">
            限值清洗
          </a-checkbox>
        </a-form-item>
      </a-form>
    </a-modal>
    <a-modal
      v-model:open="openEditModeModal"
      title="编辑模式"
      @ok="handleEditMode"
      @cancel="closeEditMode"
    >
      <a-form
        :model="mode"
        :label-col="{ span: 7 }"
        :wrapper-col="{ span: 15 }"
      >
        <a-form-item label="模式名称">
          <a-input
            v-model:value="mode.alarmname"
            placeholder="请输入模式名称"
          />
        </a-form-item>
        <a-form-item label="报警条件">
          <a-input
            v-model:value="mode.alarmcondition"
            placeholder="请输入报警条件"
          />
        </a-form-item>
      </a-form>
    </a-modal>
    <a-modal
      v-model:open="openEditModelModal"
      title="编辑模型"
      width="1200px"
      @ok="handleEditModelOk"
      @cancel="handleEditModelCancel"
    >
      <a-form
        :model="editModelForm"
        :label-col="{ span: 7 }"
        :wrapper-col="{ span: 15 }"
      >
        <a-row :gutter="16">
          <a-col :span="12">
            <a-form-item label="训练采样间隔" required>
              <a-input-number
                v-model:value="editModelForm.sampling"
                placeholder="请输入训练采样间隔"
                style="width: 100%"
              />
            </a-form-item>
          </a-col>
          <a-col :span="12">
            <a-form-item label="最小主元贡献率" required>
              <a-input-number
                v-model:value="editModelForm.rate"
                placeholder="请输入最小主元贡献率"
                style="width: 100%"
              />
            </a-form-item>
          </a-col>
        </a-row>
        <div style="display: flex; justify-content: center; margin-top: 24px;margin-bottom: 10px;">
          <PointTransfer
            v-model:selected-keys="editModelForm.selectedKeys"
            :prefill-points="model?.pointInfo || []"
            :list-style="{
              width: '500px',
              height: '450px',
            }"
          />
        </div>
      </a-form>
    </a-modal>
  </PageWrapper>
</template>

<style>
.ant-card-head-title {
  font-weight: bold;
}

.el-table .el-table__header th {
  font-weight: bold;
}
</style>
