<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 } from 'vue-router'
import {
  Button,
  Card,
  Checkbox,
  Descriptions,
  Divider,
  Form,
  FormItem,
  Input,
  InputNumber,
  Modal,
  RangePicker,
  Spin,
  Steps,
  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 {
  modelInfoApi,
  testModelApi,
  trainModelApi,
  updateModelInfo,
} from '@/api/alert/model/models'
import { getExaHistorys } from '@/api/alert/exa/index'
import { useECharts } from '@/hooks/web/useECharts'
import { useMessage } from '@/hooks/web/useMessage'

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,
    ARangePicker: RangePicker,
    AForm: Form,
    AFormItem: FormItem,
    VueECharts,
    AModal: Modal,
    AInput: Input,
    ACheckbox: Checkbox,
    AInputNumber: InputNumber,
    AButton: Button,
    ASpin: Spin,
  },
  setup() {
    const { createMessage } = useMessage()
    const route = useRoute()
    const id = route.params.id
    const model = ref(null)
    const brushActivated = ref<Set<number>>(new Set())
    const spinning = ref(false)
    const fetchModelInfo = async () => {
      const modelInfo = await modelInfoApi(id)
      model.value = modelInfo
      getHistory()
    }

    const pointData = computed(() => model.value?.pointInfo || [])
    const [pointTable] = useTable({
      columns: pointTableSchema,
      pagination: false,
      dataSource: pointData,
      scroll: { y: 300 },
    })

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

    const activeKey = ref('1')
    type RangeValue = [Dayjs, Dayjs]
    const currentDate: Dayjs = dayjs()
    const lastMonthDate: Dayjs = currentDate.subtract(1, 'day')
    const rangeValue: RangeValue = [
      dayjs('2025-2-24 00:00:00'),
      dayjs('2025-2-24 23:59:59'),
    ]
    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) {
        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,
        }
        console.log(params)
        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() {
      const params = {
        Model_id: 118,
        version: model.value?.Cur_Version ? model.value?.Cur_Version : 'v-test',
        Test_Data: {
          time: historyTime.value
            .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
      const reconData = result.reconData
      const xData = generateTimeList(
        historyTime.value,
        model.value.sampling * 1000,
      )
      historyList.value = sampleData.map((item, index) => {
        const point = model.value?.pointInfo[index]
        return {
          data: [
            item.map((t, i) => {
              return [xData[i], t]
            }),
            reconData[index].map((t, i) => {
              return [xData[i], t]
            }),
          ],
          name: `${index + 1}.${point?.description}(${point?.pointId})`,
        }
      })
      console.log(historyList.value)
    }

    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 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,
          },
        ],
      }
      console.log('option', option)
      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,
      })
      brushActivated.value.add(index)
      isInitBrush.value = true
    }

    onMounted(async () => {
      await fetchModelInfo()
    })
    const onBrushSelected = debounce((params) => {
      if (isInitBrush.value) {
        isInitBrush.value = false
        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 [st, et] = area.coordRange
          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: '', // 有效样本数（如有数据可补充）
          }
        })
        model.value.trainTime = 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 (!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() {
      model.value.para = null
      updateModelInfoDebounced()
      await getHistory()
    }

    async function trainModel() {
      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
        model.value.principal = response.Model_info.K
        updateModelInfoDebounced()
        getTestData()
        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) {
      openEditPointModal.value = true
      pointEditRecord = record
      editForm.value = {
        index,
        Upper: record?.Upper ?? '',
        Lower: record?.Lower ?? '',
        lowerBound: record?.lowerBound ?? '',
        upperBound: record?.upperBound ?? '',
        dead: record?.dead ?? false,
        limit: record?.limit ?? true,
      }
    }

    const mode = ref({
      alarmcondition: '1==1',
      alarmname: '全工况运行',
    })
    const openEditModeModal = ref<boolean>(false)

    function openEditMode() {
      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()
    }

    return {
      pointTable,
      model,
      activeKey,
      historyTime,
      historyList,
      getHistory,
      getOption,
      setChartRef,
      setEchartsRef,
      onChartFinished,
      echartsRefs,
      onBrushSelected,
      trainTimeTable,
      handleDeleteTrainTime,
      openEditPointModal,
      editPoint,
      openPointModal,
      editForm,
      trainModel,
      openEditModeModal,
      openEditMode,
      closeEditMode,
      handleEditMode,
      mode,
      spinning,
      clearModel,
    }
  },
})
</script>

<template>
  <PageWrapper content-background>
    <div>
      <a-card title="模型信息" :bordered="false">
        <template #extra>
          <a-button> 下装 </a-button>
          <a-button type="primary" style="margin-left: 6px">
            修改模型
          </a-button>
        </template>
        <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="版本">
            {{ model?.Cur_Version || "v-test" }}
          </a-descriptions-item>
          <a-descriptions-item label="评估报告">
            暂无
          </a-descriptions-item>
          <a-descriptions-item label="创建人">
            {{ model?.founder }}
          </a-descriptions-item>
          <a-descriptions-item label="创建时间">
            {{ model?.creatTime }}
          </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" @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
                  type="link"
                  danger
                  @click="handleDeleteTrainTime(index)"
                >
                  删除
                </a-button>
              </template>
            </BasicTable>
          </a-tab-pane>
          <a-tab-pane key="2" tab="测点参数">
            <BasicTable @register="pointTable">
              <template #action="{ record, index }">
                <a-button type="primary" @click="openPointModal(index, record)">
                  编辑
                </a-button>
              </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
            type="primary"
            style="margin-left: auto"
            @click="trainModel"
          >
            模型训练
          </a-button>
          <a-button
            type="primary"
            style="margin-left: 10px"
            @click="clearModel"
          >
            清除训练结果
          </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="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>
  </PageWrapper>
</template>

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

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