<script setup>
import * as echarts from 'echarts'
import { Refresh } from '@element-plus/icons-vue'
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { getExperiments, getDataPoints } from '@/api/realtimeMonitor'

const router = useRouter()

const runningExps = ref([])
const loadingList = ref(false)

// echarts instances & data state, keyed by experiment id
const chartsMap = {}       // id -> echarts instance
const dataMap = {}         // id -> data points array
const fromStepMap = {}     // id -> next from_step

const MAX_DISPLAY = 300

let listTimer = null
let dataTimer = null

// ── 数据加载 ──────────────────────────────────────────────────────────────────
const loadList = async () => {
  loadingList.value = true
  try {
    const all = await getExperiments()
    const running = all.filter((e) => e.status === 'running')
    // 清理已停止试验的图表实例
    const runningIds = new Set(running.map((e) => e.id))
    for (const id of Object.keys(chartsMap)) {
      if (!runningIds.has(Number(id))) {
        chartsMap[id]?.dispose()
        delete chartsMap[id]
        delete dataMap[id]
        delete fromStepMap[id]
      }
    }
    runningExps.value = running
  } finally {
    loadingList.value = false
  }
}

const fetchAllData = async () => {
  for (const exp of runningExps.value) {
    try {
      const from = fromStepMap[exp.id] ?? 0
      const newPts = await getDataPoints(exp.id, from)
      if (newPts.length) {
        dataMap[exp.id] = [...(dataMap[exp.id] ?? []), ...newPts]
        fromStepMap[exp.id] = dataMap[exp.id][dataMap[exp.id].length - 1].step_idx + 1
        await nextTick()
        updateChart(exp.id, exp.target_temp)
      }
    } catch {
      // ignore per-experiment errors
    }
  }
}

// ── 图表 ──────────────────────────────────────────────────────────────────────
const getOrInitChart = (expId) => {
  if (!chartsMap[expId]) {
    const el = document.getElementById(`live-chart-${expId}`)
    if (el) chartsMap[expId] = echarts.init(el)
  }
  return chartsMap[expId]
}

const updateChart = (expId, targetTemp) => {
  const c = getOrInitChart(expId)
  if (!c) return
  const pts = dataMap[expId] ?? []
  if (!pts.length) return

  const step = pts.length > MAX_DISPLAY ? Math.ceil(pts.length / MAX_DISPLAY) : 1
  const display = pts.filter((_, i) => i % step === 0)
  const xData = display.map((d) => `${d.step_idx}`)
  const actuals = display.map((d) => d.actual_temp)
  const currents = display.map((d) => d.current_output)
  const targetLine = display.map(() => targetTemp ?? null)

  c.setOption(
    {
      animation: false,
      color: ['#409EFF', '#F56C6C', '#E6A23C'],
      tooltip: {
        trigger: 'axis',
        backgroundColor: 'rgba(255,255,255,0.96)',
        borderColor: '#e2e8f0',
        borderWidth: 1,
        formatter(params) {
          if (!params?.length) return ''
          const lines = [`<b>步 ${params[0].axisValue}</b>`]
          params.forEach((p) => {
            const unit = p.seriesName === '电流输出' ? ' A' : ' °C'
            const v = p.data != null ? Number(p.data).toFixed(2) + unit : '--'
            lines.push(`${p.marker}${p.seriesName}: <b>${v}</b>`)
          })
          return lines.join('<br/>')
        },
      },
      legend: { bottom: 2, itemWidth: 14, itemHeight: 7, textStyle: { fontSize: 11, color: '#475569' } },
      grid: { top: 12, left: 8, right: 50, bottom: 40, containLabel: true },
      xAxis: {
        type: 'category',
        boundaryGap: false,
        data: xData,
        axisLabel: { color: '#94a3b8', fontSize: 10, interval: Math.max(0, Math.floor(xData.length / 6) - 1) },
        axisLine: { lineStyle: { color: '#e2e8f0' } },
      },
      yAxis: [
        {
          type: 'value',
          name: '°C',
          nameTextStyle: { color: '#64748b', fontSize: 10 },
          axisLabel: { color: '#64748b', fontSize: 10 },
          splitLine: { lineStyle: { color: '#e2e8f0' } },
        },
        {
          type: 'value',
          name: 'A',
          position: 'right',
          nameTextStyle: { color: '#E6A23C', fontSize: 10 },
          axisLabel: { color: '#E6A23C', fontSize: 10 },
          splitLine: { show: false },
          min: 0,
        },
      ],
      series: [
        {
          name: '实际温度',
          type: 'line',
          yAxisIndex: 0,
          data: actuals,
          smooth: true,
          symbol: 'none',
          lineStyle: { width: 1.5 },
        },
        {
          name: '目标温度',
          type: 'line',
          yAxisIndex: 0,
          data: targetLine,
          symbol: 'none',
          lineStyle: { width: 1, type: 'dotted', color: '#F56C6C' },
        },
        {
          name: '电流输出',
          type: 'line',
          yAxisIndex: 1,
          data: currents,
          smooth: false,
          symbol: 'none',
          lineStyle: { width: 1.5, color: '#E6A23C' },
          areaStyle: { color: '#E6A23C', opacity: 0.05 },
        },
      ],
    },
    true,
  )
}

const onResize = () => {
  Object.values(chartsMap).forEach((c) => c?.resize())
}

// ── 生命周期 ──────────────────────────────────────────────────────────────────
onMounted(async () => {
  await loadList()
  await nextTick()
  // 加载各试验初始数据
  await fetchAllData()

  listTimer = setInterval(loadList, 5000)
  dataTimer = setInterval(fetchAllData, 2000)
  window.addEventListener('resize', onResize)
})

onBeforeUnmount(() => {
  clearInterval(listTimer)
  clearInterval(dataTimer)
  window.removeEventListener('resize', onResize)
  Object.values(chartsMap).forEach((c) => c?.dispose())
})
</script>

<template>
  <div class="live-page">
    <div class="live-header">
      <span class="live-title">实时监控</span>
      <el-tag type="success" size="small" style="margin-left:10px">
        {{ runningExps.length }} 个试验运行中
      </el-tag>
      <el-button
        :icon="Refresh"
        size="small"
        plain
        :loading="loadingList"
        style="margin-left:auto"
        @click="loadList"
      >
        刷新
      </el-button>
      <el-button size="small" plain @click="router.push('/realtime-monitor')">
        前往试验管理
      </el-button>
    </div>

    <div v-if="!runningExps.length && !loadingList" class="empty-state">
      <el-empty description="当前没有正在运行的试验" :image-size="120">
        <el-button type="primary" @click="router.push('/realtime-monitor')">
          前往试验管理
        </el-button>
      </el-empty>
    </div>

    <div v-else class="exp-grid">
      <el-card
        v-for="exp in runningExps"
        :key="exp.id"
        shadow="hover"
        class="exp-card"
      >
        <template #header>
          <div class="exp-card-header">
            <span class="exp-name">{{ exp.name }}</span>
            <el-tag type="success" size="small" effect="plain">运行中</el-tag>
          </div>
          <div class="exp-meta">
            <span>目标 {{ exp.target_temp?.toFixed(1) }} °C</span>
            <span>步数 {{ exp.total_steps }}</span>
            <span>{{ exp.model_name }}</span>
          </div>
        </template>

        <div
          :id="`live-chart-${exp.id}`"
          class="mini-chart"
        >
          <div v-if="!(dataMap[exp.id]?.length)" class="chart-placeholder">
            <el-icon class="is-loading" style="font-size:20px;color:#409EFF"><Refresh /></el-icon>
            <span>等待数据…</span>
          </div>
        </div>
      </el-card>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.live-page {
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
}

.live-header {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.live-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
}

.empty-state {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.exp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(480px, 1fr));
  gap: 16px;
  align-content: start;
}

.exp-card {
  :deep(.el-card__header) {
    padding: 10px 16px 6px;
  }

  :deep(.el-card__body) {
    padding: 0;
  }
}

.exp-card-header {
  display: flex;
  align-items: center;
  gap: 8px;
}

.exp-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.exp-meta {
  display: flex;
  gap: 12px;
  font-size: 12px;
  color: var(--text-tertiary);
  margin-top: 4px;
}

.mini-chart {
  height: 240px;
  width: 100%;
  position: relative;
}

.chart-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: #94a3b8;
  font-size: 13px;
}
</style>
