<template>
  <div class="app-container">
    <el-card shadow="never">
      <el-form :inline="true" :model="queryForm" size="small">
        <el-form-item label="时间范围">
          <el-date-picker
            v-model="timeRange"
            type="datetimerange"
            value-format="YYYY-MM-DD HH:mm:ss"
            range-separator="至"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            style="width: 380px"
          />
        </el-form-item>
        <el-form-item label="单测点">
          <el-select
            v-model="queryForm.monitorId"
            filterable
            clearable
            placeholder="请选择测点"
            style="width: 220px"
          >
            <el-option
              v-for="item in monitorOptions"
              :key="item.monitorId"
              :label="item.monitorName || item.monitorId"
              :value="item.monitorId"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="多测点对比">
          <el-select
            v-model="queryForm.monitorIds"
            multiple
            filterable
            clearable
            collapse-tags
            :max-collapse-tags="3"
            placeholder="请选择 2~10 个测点"
            style="width: 320px"
            @change="handleMonitorIdsChange"
          >
            <el-option
              v-for="item in monitorOptions"
              :key="item.monitorId"
              :label="item.monitorName || item.monitorId"
              :value="item.monitorId"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card shadow="never" class="mt-4">
      <template #header>
        <div class="card-header">
          <span class="font-bold">
            分钟趋势
            <el-tag v-if="autoDowngradeToHour" type="warning" size="small" class="ml-2">
              跨天自动聚合为小时
            </el-tag>
          </span>
          <HelpButton title="分钟趋势" :content="TREND_HELP" />
        </div>
      </template>
      <div ref="minuteChartRef" class="chart-container-lg" />
    </el-card>

    <el-card shadow="never" class="mt-4">
      <template #header>
        <div class="card-header">
          <span class="font-bold">小时趋势（含最高/最低温带）</span>
          <HelpButton title="小时趋势" :content="TREND_HELP" />
        </div>
      </template>
      <div ref="hourlyChartRef" class="chart-container-lg" />
    </el-card>

    <el-card shadow="never" class="mt-4">
      <template #header>
        <div class="card-header">
          <span class="font-bold">
            多测点对比趋势
            <!--
              粒度提示：后端根据跨度自动选择分钟 / 15 分钟 / 小时级聚合，
              这里把粒度以标签形式暴露给用户，避免误读折点密度。
            -->
            <el-tag v-if="multiCompareGranularityLabel" type="info" size="small" class="ml-2">
              当前粒度：{{ multiCompareGranularityLabel }}
            </el-tag>
          </span>
          <HelpButton title="多测点对比趋势" :content="TREND_HELP" />
        </div>
      </template>
      <div ref="multiCompareChartRef" class="chart-container-lg" />
    </el-card>

    <el-card v-if="queryForm.monitorId" shadow="never" class="mt-4">
      <template #header>
        <div class="card-header">
          <span class="font-bold">温度变化率</span>
          <HelpButton title="温度变化率" :content="TREND_HELP" />
        </div>
      </template>
      <div ref="changeRateChartRef" class="chart-container-lg" />
    </el-card>

    <el-card shadow="never" class="mt-4">
      <template #header>
        <div class="card-header">
          <span class="font-bold">日均温趋势</span>
          <HelpButton title="日均温趋势" :content="TREND_HELP" />
        </div>
      </template>
      <div ref="dailyChartRef" class="chart-container" />
    </el-card>

    <el-card shadow="never" class="mt-4">
      <template #header>
        <div class="card-header">
          <span class="font-bold">峰谷时刻表</span>
          <HelpButton title="峰谷时刻表" :content="TREND_HELP" />
        </div>
      </template>
      <el-table :data="peakValleyList" stripe size="small">
        <el-table-column prop="monitorId" label="测点ID" width="150" />
        <el-table-column prop="monitorName" label="测点名称" width="180" />
        <el-table-column prop="peakTemp" label="峰值温度" width="100" align="right">
          <template #default="{ row }">
            <span class="text-red-500 font-bold">{{ row.peakTemp?.toFixed(2) }}℃</span>
          </template>
        </el-table-column>
        <el-table-column prop="peakTime" label="峰值时间" width="200" />
        <el-table-column prop="valleyTemp" label="谷值温度" width="100" align="right">
          <template #default="{ row }">
            <span class="text-blue-500 font-bold">{{ row.valleyTemp?.toFixed(2) }}℃</span>
          </template>
        </el-table-column>
        <el-table-column prop="valleyTime" label="谷值时间" width="200" />
      </el-table>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, nextTick, type Ref } from 'vue';
import * as echarts from 'echarts';
import { ElMessage } from 'element-plus';
import {
  getMinuteTrend,
  getHourlyTrend,
  getDailyTrend,
  getPeakValley,
  getMultiCompareTrend,
  getChangeRateTrend,
  listTempMonitors
} from '@/api/ems/report/tempBoard';
import type {
  TempBoardQuery,
  TempBoardTrendVO,
  TempBoardMonitorOptionVO
} from '@/api/ems/report/tempBoard';
import HelpButton from '../components/HelpButton.vue';
import { TREND_HELP } from '../components/helpContent';
import { useChartResize } from '../components/useChartResize';

defineOptions({ name: 'TempBoardTrend' });

const timeRange = ref<[string, string]>(['', '']);
const queryForm = reactive<TempBoardQuery>({
  monitorId: '',
  monitorIds: [],
  rapidRiseThreshold: 1.0
});
const loading = ref(false);
// 后端 getMinuteTrend 在跨度 >24h 时会自动返回小时粒度；前端同步判断并提示用户。
const autoDowngradeToHour = ref(false);
// 多测点对比的实际聚合粒度，由后端 VO.granularity 透传。
const multiCompareGranularityLabel = ref('');
const monitorOptions = ref<TempBoardMonitorOptionVO[]>([]);
const minuteChartRef = ref<HTMLElement>();
const hourlyChartRef = ref<HTMLElement>();
const multiCompareChartRef = ref<HTMLElement>();
const changeRateChartRef = ref<HTMLElement>();
const dailyChartRef = ref<HTMLElement>();
const peakValleyList = ref<TempBoardTrendVO[]>([]);

const { getChart } = useChartResize(
  minuteChartRef,
  hourlyChartRef,
  multiCompareChartRef,
  changeRateChartRef,
  dailyChartRef
);

/** 初始化默认时间范围：昨天8:30 ~ 今天8:30 */
function initTimeRange() {
  const now = new Date();
  const end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 30, 0);
  const start = new Date(end.getTime() - 24 * 3600 * 1000);
  const p = (n: number) => n.toString().padStart(2, '0');
  const fmt = (d: Date) =>
    `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
  timeRange.value = [fmt(start), fmt(end)];
}

function buildLineSeries(name: string, data: number[], color: string, extra: Record<string, any> = {}) {
  // 默认关闭折点，hover 时由 ECharts 自动浮现；长跨度 LTTB 后千点渲染不掉帧。
  return {
    name,
    type: 'line',
    sampling: 'lttb',
    showSymbol: false,
    symbol: 'none',
    data,
    ...extra,
    lineStyle: { width: 2, color, ...(extra.lineStyle ?? {}) },
    itemStyle: { color, ...(extra.itemStyle ?? {}) }
  };
}

function renderLineChart(el: Ref<HTMLElement | undefined>, data: TempBoardTrendVO[], options?: { showBand?: boolean }) {
  const chart = getChart(el);
  if (!chart) return;
  if (!data.length) {
    renderChartPlaceholder(el, '当前条件暂无趋势数据');
    return;
  }
  const times = data.map((d) => d.statTime || '');
  const series: any[] = [
    buildLineSeries('平均温度', data.map((d) => d.avgTemp), '#409eff', {
      smooth: true,
      areaStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: 'rgba(64,158,255,0.3)' },
          { offset: 1, color: 'rgba(64,158,255,0.02)' }
        ])
      }
    })
  ];
  if (options?.showBand) {
    series.push(
      buildLineSeries('最高温度', data.map((d) => d.maxTemp), '#f56c6c', {
        lineStyle: { width: 1, type: 'dashed' },
        itemStyle: { opacity: 0.6 },
        symbol: 'none'
      }),
      buildLineSeries('最低温度', data.map((d) => d.minTemp), '#67c23a', {
        lineStyle: { width: 1, type: 'dashed' },
        itemStyle: { opacity: 0.6 },
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: 'rgba(64,158,255,0.15)' },
            { offset: 1, color: 'rgba(64,158,255,0.05)' }
          ])
        },
        symbol: 'none'
      })
    );
  }
  chart.setOption({
    tooltip: {
      trigger: 'axis',
      formatter: (params: any) => {
        let html = `<b>${params[0]?.axisValue ?? ''}</b><br/>`;
        params.forEach((p: any) => {
          html += `${p.marker} ${p.seriesName}: <b>${p.value}℃</b><br/>`;
        });
        return html;
      }
    },
    legend: { data: series.map((s) => s.name), top: 0, textStyle: { color: '#666' } },
    grid: { left: 60, right: 30, top: 40, bottom: 30 },
    xAxis: { type: 'category', data: times, axisLabel: { color: '#999' }, boundaryGap: false },
    yAxis: { type: 'value', name: '℃', axisLabel: { color: '#666' }, splitLine: { lineStyle: { type: 'dashed' } } },
    series
  });
}

/**
 * 把后端的粒度枚举映射为面向用户的中文标签。
 * 默认 → 空字符串（不显示标签），避免接口缺字段时强行渲染。
 */
function mapGranularityLabel(value: string | undefined): string {
  switch (value) {
    case 'MINUTE':
      return '分钟';
    case 'FIFTEEN_MINUTE':
      return '15 分钟';
    case 'HOUR':
      return '小时';
    default:
      return '';
  }
}

function renderMultiCompareChart(data: TempBoardTrendVO[]) {
  const chart = getChart(multiCompareChartRef);
  if (!chart) return;
  if (!data.length) {
    // 无数据时清理粒度标签，不要留着上次查询的残值误导用户。
    multiCompareGranularityLabel.value = '';
    renderChartPlaceholder(multiCompareChartRef, '请选择 2~10 个测点后查看多测点对比趋势');
    return;
  }
  // 后端给每行 VO 都写了一致的 granularity，这里读首行即可。
  multiCompareGranularityLabel.value = mapGranularityLabel(data[0]?.granularity);
  const times = Array.from(new Set(data.map((item) => item.statTime || '')));
  const groupMap = new Map<string, { monitorName: string; values: Map<string, number> }>();
  data.forEach((item) => {
    const key = item.monitorId || item.monitorName || '';
    if (!groupMap.has(key)) {
      groupMap.set(key, {
        monitorName: item.monitorName || item.monitorId || '未命名测点',
        values: new Map<string, number>()
      });
    }
    groupMap.get(key)?.values.set(item.statTime || '', item.avgTemp);
  });
  const series = Array.from(groupMap.entries()).map(([monitorId, group]) => ({
    name: group.monitorName || monitorId,
    type: 'line',
    sampling: 'lttb',
    smooth: true,
    symbol: 'none',
    data: times.map((time) => group.values.get(time) ?? null)
  }));
  chart.setOption({
    tooltip: { trigger: 'axis' },
    legend: { top: 0, textStyle: { color: '#666' } },
    grid: { left: 60, right: 30, top: 40, bottom: 30 },
    xAxis: { type: 'category', data: times, boundaryGap: false, axisLabel: { color: '#999' } },
    yAxis: { type: 'value', name: '℃', axisLabel: { color: '#666' }, splitLine: { lineStyle: { type: 'dashed' } } },
    series
  });
}

function renderChangeRateChart(data: TempBoardTrendVO[]) {
  const chart = getChart(changeRateChartRef);
  if (!chart) return;
  if (!data.length) {
    renderChartPlaceholder(changeRateChartRef, '当前测点暂无变化率数据');
    return;
  }
  const threshold = queryForm.rapidRiseThreshold ?? 1.0;
  chart.setOption({
    tooltip: {
      trigger: 'axis',
      formatter: (params: any) => {
        const item = params?.[0];
        return `${item?.axisValue ?? ''}<br/>变化率: <b>${item?.data?.value ?? item?.value}℃/分钟</b>`;
      }
    },
    grid: { left: 60, right: 30, top: 30, bottom: 30 },
    xAxis: {
      type: 'category',
      data: data.map((item) => item.statTime || ''),
      boundaryGap: false,
      axisLabel: { color: '#999' }
    },
    yAxis: {
      type: 'value',
      name: '℃/分钟',
      axisLabel: { color: '#666' },
      splitLine: { lineStyle: { type: 'dashed' } }
    },
    series: [
      {
        name: '变化率',
        type: 'line',
        sampling: 'lttb',
        smooth: true,
        lineStyle: { width: 2, color: '#409eff' },
        itemStyle: { color: '#409eff' },
        data: data.map((item) => ({
          value: item.changeRate,
          itemStyle: Math.abs(item.changeRate) >= threshold ? { color: '#f56c6c' } : undefined
        })),
        markLine: {
          symbol: 'none',
          label: { formatter: `阈值 ${threshold}℃/分钟` },
          lineStyle: { type: 'dashed', color: '#f56c6c' },
          data: [{ yAxis: threshold }, { yAxis: -threshold }]
        }
      }
    ]
  });
}

function renderChartPlaceholder(el: Ref<HTMLElement | undefined>, title: string) {
  const chart = getChart(el);
  if (!chart) return;
  chart.clear();
  chart.setOption({
    title: {
      text: title,
      left: 'center',
      top: 'middle',
      textStyle: { color: '#999', fontSize: 14, fontWeight: 'normal' }
    },
    xAxis: { show: false },
    yAxis: { show: false },
    series: []
  });
}

function handleMonitorIdsChange(value: string[]) {
  if (value.length > 10) {
    queryForm.monitorIds = value.slice(0, 10);
    ElMessage.warning('多测点对比最多选择 10 个测点');
  }
}

async function loadMonitorOptions() {
  const { data } = await listTempMonitors();
  monitorOptions.value = data;
}

async function handleQuery() {
  if (timeRange.value?.[0]) {
    queryForm.startTime = timeRange.value[0];
    queryForm.endTime = timeRange.value[1];
  }
  queryForm.monitorId = queryForm.monitorId?.trim();
  queryForm.monitorIds = (queryForm.monitorIds ?? []).filter(Boolean);
  // 与后端 Service 的 24h 阈值对齐：跨天时 /trend/minute 会回落到小时聚合。
  const spanMs =
    timeRange.value?.[0] && timeRange.value?.[1]
      ? new Date(timeRange.value[1]).getTime() - new Date(timeRange.value[0]).getTime()
      : 0;
  autoDowngradeToHour.value = Boolean(queryForm.monitorId) && spanMs > 24 * 3600 * 1000;
  loading.value = true;
  try {
    // 跨天时后端 getMinuteTrend 已自动回落到小时聚合，这里不再触发 getHourlyTrend，
    // 避免同一时刻对数据库打 2 次几乎等价的小时聚合 SQL；前端通过复用 minute 结果
    // 来渲染小时趋势卡，保持展示语义不变。
    const needHourlyRequest = Boolean(queryForm.monitorId) && !autoDowngradeToHour.value;
    const [
      dailyRes,
      peakValleyRes,
      minuteRes,
      hourlyRes,
      multiCompareRes,
      changeRateRes
    ] = await Promise.all([
      getDailyTrend(queryForm),
      getPeakValley(queryForm),
      queryForm.monitorId ? getMinuteTrend(queryForm) : Promise.resolve({ data: [] }),
      needHourlyRequest ? getHourlyTrend(queryForm) : Promise.resolve({ data: [] }),
      (queryForm.monitorIds?.length ?? 0) >= 2 ? getMultiCompareTrend(queryForm) : Promise.resolve({ data: [] }),
      queryForm.monitorId ? getChangeRateTrend(queryForm) : Promise.resolve({ data: [] })
    ]);
    peakValleyList.value = peakValleyRes.data;
    await nextTick();

    if (queryForm.monitorId) {
      renderLineChart(minuteChartRef, minuteRes.data);
      // 自动降级时直接复用 minute 的小时聚合结果，不再发起额外的 hourly 请求。
      const hourlyData = needHourlyRequest ? hourlyRes.data : minuteRes.data;
      renderLineChart(hourlyChartRef, hourlyData, { showBand: true });
      renderChangeRateChart(changeRateRes.data);
    } else {
      renderChartPlaceholder(minuteChartRef, '请选择测点后查看分钟趋势');
      renderChartPlaceholder(hourlyChartRef, '请选择测点后查看小时趋势');
    }

    renderMultiCompareChart(multiCompareRes.data);
    renderLineChart(dailyChartRef, dailyRes.data, { showBand: true });
  } finally {
    loading.value = false;
  }
}

onMounted(async () => {
  initTimeRange();
  await loadMonitorOptions();
  await handleQuery();
});
</script>

<style scoped>
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.chart-container {
  width: 100%;
  min-height: 320px;
}

.chart-container-lg {
  width: 100%;
  min-height: 360px;
}
</style>
