<template>
  <div v-loading="loading" class="app-container report-page">
    <el-card shadow="never" class="hero-card">
      <div class="hero-head">
        <div>
          <div class="hero-title">{{ reportTitle }}</div>
          <div class="hero-desc">
            {{ reportSubtitle }}
          </div>
        </div>
        <div class="hero-actions">
          <el-button size="mini" @click="goBack">返回</el-button>
          <el-button type="primary" size="mini" icon="el-icon-refresh" @click="handleQuery">刷新报表</el-button>
        </div>
      </div>

      <el-form class="query-form" :inline="true" :model="queryForm" size="small" label-width="86px">
        <el-form-item label="分析范围">
          <el-tag size="small" effect="dark">{{ selectionSummary }}</el-tag>
        </el-form-item>
        <el-form-item label="范围名称">
          <el-input v-model="queryForm.selectionLabel" disabled style="width: 240px" />
        </el-form-item>
        <el-form-item label="设备数量">
          <el-tag size="small" effect="plain">{{ deviceCount }} 台</el-tag>
        </el-form-item>
        <el-form-item label="设备类型">
          <el-tag size="small" effect="plain">{{ monitorTypeLabel }}</el-tag>
        </el-form-item>
        <el-form-item label="记录时间">
          <el-date-picker
            v-model="daterangeRecordTime"
            type="datetimerange"
            value-format="yyyy-MM-dd HH:mm:ss"
            range-separator="-"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            style="width: 340px"
          />
        </el-form-item>
        <el-form-item label="采样间隔">
          <el-input-number v-model="queryForm.samplingInterval" :min="1" :max="1440" controls-position="right" style="width: 122px" />
          <span class="form-suffix">分钟/点</span>
        </el-form-item>
        <el-form-item v-if="isVibrationSource" label="主看参数">
          <el-select v-model="queryForm.vibrationParam" style="width: 160px" @change="handleQuery">
            <el-option label="振动速度" value="vibrationSpeed" />
            <el-option label="振动位移" value="vibrationDisplacement" />
            <el-option label="振动加速度" value="vibrationAcceleration" />
            <el-option label="振动温度" value="vibrationTemp" />
          </el-select>
        </el-form-item>
        <el-form-item label="主看指标">
          <el-select v-model="queryForm.primaryMetricField" style="width: 180px" placeholder="请选择主看指标" @change="handlePrimaryMetricChange">
            <el-option v-for="item in availablePrimaryMetricOptions" :key="item.field" :label="item.label" :value="item.field" />
          </el-select>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card shadow="never" class="selector-card">
      <div class="selector-head">
        <div class="selector-title">分析选择器</div>
        <div class="selector-desc">在报表页内直接切换能源类型和设备范围，单能源、多能源、单设备、多设备都能快速切换</div>
      </div>
      <div class="energy-toolbar">
        <el-checkbox-group v-model="selectedEnergyTypes" @change="handleEnergyTypeChange">
          <el-checkbox-button v-for="item in availableEnergyOptions" :key="item.type" :label="item.type">
            {{ item.label }}<span class="energy-count">({{ item.deviceCount }})</span>
          </el-checkbox-button>
        </el-checkbox-group>
      </div>
      <div class="selector-summary">
        <el-tag size="small" effect="plain">{{ energySelectionSummary }}</el-tag>
        <el-tag size="small" effect="plain">{{ deviceSelectionSummary }}</el-tag>
      </div>
      <div v-loading="treeLoading" class="tree-panel">
        <el-tree
          ref="reportTree"
          node-key="id"
          :data="filteredMonitorTreeOptions"
          :props="treeProps"
          default-expand-all
          highlight-current
          :expand-on-click-node="false"
          @node-click="handleTreeNodeClick"
        />
      </div>
    </el-card>

    <div class="overview-grid">
      <div class="overview-card">
        <div class="overview-label">采样记录数</div>
        <div class="overview-value">{{ rawRecords.length }}</div>
        <div class="overview-foot">本次分析窗口内的真实采样点</div>
      </div>
      <div class="overview-card">
        <div class="overview-label">分析对象</div>
        <div class="overview-value overview-text">{{ analysisObjectValue }}</div>
        <div class="overview-foot">{{ analysisObjectFoot }}</div>
      </div>
      <div class="overview-card">
        <div class="overview-label">对比设备数</div>
        <div class="overview-value">{{ deviceCount }}</div>
        <div class="overview-foot">单设备、设备组、全设备均可进入报表</div>
      </div>
      <div class="overview-card">
        <div class="overview-label">活跃指标数</div>
        <div class="overview-value">{{ metricConfigs.length }}</div>
        <div class="overview-foot">{{ metricDescription }}</div>
      </div>
      <div class="overview-card">
        <div class="overview-label">主看指标</div>
        <div class="overview-value">{{ primaryMetric ? primaryMetric.label : '--' }}</div>
        <div class="overview-foot">{{ primaryMetricFoot }}</div>
      </div>
      <div class="overview-card">
        <div class="overview-label">数据覆盖率</div>
        <div class="overview-value">{{ formatPercent(coverageRatio) }}</div>
        <div class="overview-foot">有效值占理论值的比例</div>
      </div>
    </div>

    <div v-if="metricCards.length" class="metric-grid">
      <div v-for="item in metricCards" :key="item.field" class="metric-card" :style="{ borderTopColor: item.color }">
        <div class="metric-name">{{ item.label }}</div>
        <div class="metric-value">
          {{ formatValue(item.latest) }}<span>{{ item.unit }}</span>
        </div>
        <div class="metric-foot">均值 {{ formatValue(item.avg) }}{{ item.unit }}</div>
        <div class="metric-foot">峰值 {{ formatValue(item.max) }}{{ item.unit }}</div>
      </div>
    </div>

    <div v-if="!reportReady" class="empty-panel">
      <i class="el-icon-data-analysis empty-icon" />
      <p>当前选择范围在该时间窗口内没有可用于分析的真实数据，请调整时间、采样间隔或分析范围后重试。</p>
    </div>

    <template v-else>
      <div class="chart-grid two-col">
        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>{{ hasMultiDevice ? '设备对比趋势图' : '多指标趋势图' }}</span>
              <span class="card-tip">{{ hasMultiDevice ? '按主看指标对多设备走势做横向比较' : '保留时间顺序回看单设备波动' }}</span>
            </div>
          </template>
          <Chart ref="trendChart" class="chart chart-lg" />
        </el-card>

        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>仪表盘总览</span>
              <span class="card-tip">{{ hasMultiDevice ? '展示群组主看指标的整体水平' : '展示单设备最新关键值' }}</span>
            </div>
          </template>
          <Chart ref="gaugeChart" class="chart chart-lg" />
        </el-card>
      </div>

      <div class="chart-grid two-col">
        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>桑葚流向图</span>
              <span class="card-tip">{{ hasMultiDevice ? '看设备流向高位、关注、平稳区间' : '看指标流向高位、关注、平稳区间' }}</span>
            </div>
          </template>
          <Chart ref="sankeyChart" class="chart" />
        </el-card>

        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>漏斗图</span>
              <span class="card-tip">{{ hasMultiDevice ? '筛出重点设备' : '筛出重点采样记录' }}</span>
            </div>
          </template>
          <Chart ref="funnelChart" class="chart" />
        </el-card>
      </div>

      <div class="chart-grid three-col">
        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>覆盖率水球图</span>
              <span class="card-tip">检视当前窗口数据完整性</span>
            </div>
          </template>
          <Chart ref="liquidChart" class="chart chart-sm" />
        </el-card>

        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>雷达轮廓图</span>
              <span class="card-tip">{{ hasMultiDevice ? '对比群组均值与峰值轮廓' : '对比单设备最新值与均值轮廓' }}</span>
            </div>
          </template>
          <Chart ref="radarChart" class="chart chart-sm" />
        </el-card>

        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>小时均值图</span>
              <span class="card-tip">定位波动集中的时间段</span>
            </div>
          </template>
          <Chart ref="hourlyChart" class="chart chart-sm" />
        </el-card>
      </div>

      <div v-if="hasMultiDevice && deviceStats.length" class="chart-grid two-col">
        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>设备排名对比图</span>
              <span class="card-tip">按主看指标均值与最新值综合比较设备状态</span>
            </div>
          </template>
          <Chart ref="deviceRankChart" class="chart" />
        </el-card>

        <el-card shadow="hover" class="chart-card">
          <template v-slot:header>
            <div class="card-header">
              <span>设备散点图</span>
              <span class="card-tip">同时观察设备均值、峰值与采样量</span>
            </div>
          </template>
          <Chart ref="deviceScatterChart" class="chart" />
        </el-card>
      </div>
    </template>
  </div>
</template>

<script setup lang="ts">
import { ElMessage } from 'element-plus';
import Chart from '@/components/Charts/Chart.vue';
import { getMonitorInfoTree } from '@/api/ems/base/baseMonitorInfo';
import { getRecordIotenvInstantReportData } from '@/api/ems/record/recordIotenvInstant';

defineOptions({
  name: 'RecordIotenvInstantDashboard'
} as any);

const { proxy } = getCurrentInstance() as any;

const deviceRankChart = ref<any>();
const deviceScatterChart = ref<any>();
const funnelChart = ref<any>();
const gaugeChart = ref<any>();
const hourlyChart = ref<any>();
const liquidChart = ref<any>();
const radarChart = ref<any>();
const reportTree = ref<any>();
const sankeyChart = ref<any>();
const trendChart = ref<any>();

// 这里统一通过工厂函数重建表单，避免弹窗在新增/编辑切换时残留上一条业务数据。
const createFormData = () => ({});

// 这里保留原页面字段结构，优先保证 EMS 业务行为与接口入参不发生漂移。
const state = reactive({
  loading: false,
  reportReady: false,
  rawRecords: [],
  metricConfigs: [],
  metricCards: [],
  deviceStats: [],
  coverageRatio: 0,
  primaryMetric: null,
  deviceDisplayMap: {},
  monitorTreeOptions: [],
  selectedEnergyTypes: [],
  treeLoading: false,
  currentTreeNodeId: null,
  daterangeRecordTime: [],
  queryForm: {
    source: 'iot',
    compareScope: 'single',
    monitorId: '',
    monitorIds: [],
    monitorName: '',
    selectionLabel: '',
    monitorType: '',
    samplingInterval: 5,
    vibrationParam: 'vibrationSpeed',
    primaryMetricField: ''
  },
  treeProps: {
    label: 'label',
    children: 'children'
  }
} as any);

const {
  coverageRatio,
  currentTreeNodeId,
  daterangeRecordTime,
  deviceDisplayMap,
  deviceStats,
  loading,
  metricCards,
  metricConfigs,
  monitorTreeOptions,
  primaryMetric,
  queryForm,
  rawRecords,
  reportReady,
  selectedEnergyTypes,
  treeLoading,
  treeProps
} = toRefs(state);

// 统一把多设备/来源类型判断显式化，避免 Vue2 风格的 this 隐式上下文残留到组合式 API 页面里。
const isVibrationSource = computed(() => queryForm.value.source === 'vibration');
const deviceCount = computed(() => {
  if (queryForm.value.monitorIds && queryForm.value.monitorIds.length > 0) {
    return queryForm.value.monitorIds.length;
  }
  return queryForm.value.monitorId ? 1 : 0;
});
const hasMultiDevice = computed(
  () => (queryForm.value.monitorIds && queryForm.value.monitorIds.length > 1) || ['group', 'all'].includes(queryForm.value.compareScope)
);
const chartRefMap = {
  deviceRankChart,
  deviceScatterChart,
  funnelChart,
  gaugeChart,
  hourlyChart,
  liquidChart,
  radarChart,
  sankeyChart,
  trendChart
} as const;

const initializeReport = async () => {
  initQueryFromRoute();
  await loadMonitorTree();
  applyInitialSelection();
  handleQuery();
};

const initQueryFromRoute = () => {
  const { query } = proxy?.$route;
  const selectionCacheKey = query.selectionKey || 'recordIotenvInstantDashboardSelection';
  const selectionCacheText = window.sessionStorage.getItem(selectionCacheKey);
  let selectionCache = {};
  try {
    selectionCache = selectionCacheText ? JSON.parse(selectionCacheText) : {};
  } catch (error) {
    selectionCache = {};
  }
  const monitorIds = (query.monitorIds || '')
    .split(',')
    .map((item) => item.trim())
    .filter((item) => item);
  queryForm.value.source = query.source || 'iot';
  queryForm.value.compareScope = query.compareScope || (monitorIds.length > 1 ? 'group' : 'single');
  queryForm.value.monitorId = query.monitorId || '';
  queryForm.value.monitorIds = monitorIds;
  queryForm.value.monitorName = query.monitorName || query.monitorId || '';
  queryForm.value.selectionLabel = query.selectionLabel || selectionCache.selectionLabel || query.monitorName || '当前分析范围';
  queryForm.value.monitorType = query.monitorType || selectionCache.monitorType || '';
  queryForm.value.samplingInterval = Number(query.samplingInterval || 5);
  queryForm.value.vibrationParam = query.vibrationParam || 'vibrationSpeed';
  queryForm.value.primaryMetricField = query.primaryMetricField || '';
  deviceDisplayMap.value = selectionCache.deviceDisplayMap || {};
  selectedEnergyTypes.value = parseMonitorTypes(query.monitorType || selectionCache.monitorType || '');
  daterangeRecordTime.value = [query.beginRecordTime || '', query.endRecordTime || ''];
};

const loadMonitorTree = async () => {
  treeLoading.value = true;
  try {
    const requestData = isVibrationSource.value
      ? {
          monitorType: 10
        }
      : {
          monitorTypeList: [5, 6, 7]
        };
    const response = await getMonitorInfoTree(requestData);
    monitorTreeOptions.value = response.data || [];
    deviceDisplayMap.value = Object.assign({}, buildDeviceDisplayMap(monitorTreeOptions.value), deviceDisplayMap.value);
    if (!selectedEnergyTypes.value.length) {
      selectedEnergyTypes.value = monitorTreeOptions.value.map((item) => item.type);
    }
  } finally {
    treeLoading.value = false;
  }
};

const parseMonitorTypes = (typeText) => {
  return String(typeText || '')
    .split(',')
    .map((item) => Number(item))
    .filter((item) => !Number.isNaN(item));
};

const buildDeviceDisplayMap = (nodes) => {
  return (nodes || []).reduce((accumulator, item) => {
    if (item.code && (!item.children || !item.children.length)) {
      accumulator[item.code] = {
        label: item.label,
        type: item.type
      };
    }
    if (item.children && item.children.length) {
      Object.assign(accumulator, buildDeviceDisplayMap(item.children));
    }
    return accumulator;
  }, {});
};

const applyInitialSelection = () => {
  const availableTypes = monitorTreeOptions.value.map((item) => item.type);
  selectedEnergyTypes.value = selectedEnergyTypes.value.filter((item) => availableTypes.includes(item));
  if (!selectedEnergyTypes.value.length) {
    selectedEnergyTypes.value = availableTypes;
  }
  const routeIds =
    queryForm.value.monitorIds && queryForm.value.monitorIds.length
      ? queryForm.value.monitorIds
      : queryForm.value.monitorId
        ? [queryForm.value.monitorId]
        : [];
  if (!routeIds.length) {
    applySelectionByEnergyTypes(false);
    return;
  }
  const routeSelection = buildSelectionByMonitorIds(routeIds);
  if (routeSelection.monitorIds.length) {
    applySelection(routeSelection, false);
    currentTreeNodeId.value = routeSelection.nodeId;
    return;
  }
  applySelectionByEnergyTypes(false);
};

const getLeafNodes = (nodes) => {
  let result = [];
  (nodes || []).forEach((item) => {
    if (item.children && item.children.length) {
      result = result.concat(getLeafNodes(item.children));
      return;
    }
    if (item.code) {
      result.push(item);
    }
  });
  return result;
};

const buildSelectionByNodes = (nodes, selectionLabel, compareScope) => {
  const leafNodes = getLeafNodes(nodes);
  const monitorIds = leafNodes.map((item) => item.code);
  const typeList = leafNodes.map((item) => item.type).filter((item) => item !== null && item !== undefined);
  const firstNode = leafNodes[0] || {};
  return {
    compareScope: compareScope || (monitorIds.length > 1 ? 'group' : 'single'),
    monitorId: monitorIds.length === 1 ? monitorIds[0] : '',
    monitorIds,
    monitorName: monitorIds.length === 1 ? firstNode.label || selectionLabel : selectionLabel,
    selectionLabel,
    monitorType: Array.from(new Set(typeList)).join(','),
    nodeId: firstNode.id || null
  };
};

const buildSelectionByMonitorIds = (monitorIds) => {
  const nodeMap = {};
  getLeafNodes(monitorTreeOptions.value).forEach((item) => {
    nodeMap[item.code] = item;
  });
  const leafNodes = monitorIds.map((item) => nodeMap[item]).filter(Boolean);
  if (!leafNodes.length) {
    return {
      compareScope: 'all',
      monitorId: '',
      monitorIds: [],
      monitorName: '',
      selectionLabel: '当前分析范围',
      monitorType: '',
      nodeId: null
    };
  }
  const compareScope = leafNodes.length > 1 ? 'group' : 'single';
  const selectionLabel = leafNodes.length > 1 ? `选中设备组(${leafNodes.length}台)` : leafNodes[0].label;
  return buildSelectionByNodes(leafNodes, selectionLabel, compareScope);
};

const applySelectionByEnergyTypes = (shouldQuery = true) => {
  const selectedRoots = monitorTreeOptions.value.filter((item) => selectedEnergyTypes.value.includes(item.type));
  if (!selectedRoots.length) {
    return;
  }
  const energyLabels = selectedRoots.map((item) => item.label);
  const selectionLabel = energyLabels.length === 1 ? `${energyLabels[0]}设备组` : `${energyLabels.join(' / ')}联合分析`;
  const compareScope = selectedRoots.length > 1 ? 'all' : undefined;
  applySelection(buildSelectionByNodes(selectedRoots, selectionLabel, compareScope), shouldQuery);
  currentTreeNodeId.value = null;
};

const applySelection = (selection, shouldQuery = true) => {
  queryForm.value.compareScope = selection.compareScope;
  queryForm.value.monitorId = selection.monitorId;
  queryForm.value.monitorIds = selection.monitorIds;
  queryForm.value.monitorName = selection.monitorName;
  queryForm.value.selectionLabel = selection.selectionLabel;
  queryForm.value.monitorType = selection.monitorType;
  if (shouldQuery) {
    handleQuery();
  }
};

const handleEnergyTypeChange = (value) => {
  if (!value || !value.length) {
    nextTick(() => {
      selectedEnergyTypes.value = monitorTreeOptions.value.length ? [monitorTreeOptions.value[0].type] : [];
    });
    ElMessage.warning('至少保留一种能源类型用于分析');
    return;
  }
  applySelectionByEnergyTypes();
};

const handleTreeNodeClick = (data) => {
  if (!data) {
    return;
  }
  currentTreeNodeId.value = data.id;
  if (data.children && data.children.length) {
    selectedEnergyTypes.value = [data.type];
    applySelection(buildSelectionByNodes(data.children, `${data.label}设备组`, 'group'));
    return;
  }
  selectedEnergyTypes.value = [data.type];
  applySelection(buildSelectionByNodes([data], data.label, 'single'));
};

const handleQuery = async () => {
  if (!deviceCount.value) {
    ElMessage.warning('当前没有可分析的设备范围');
    return;
  }
  if (!daterangeRecordTime.value || daterangeRecordTime.value.length !== 2) {
    ElMessage.warning('请选择完整的记录时间范围');
    return;
  }
  loading.value = true;
  reportReady.value = false;
  try {
    const { data } = await getRecordIotenvInstantReportData(buildRequestQuery());
    rawRecords.value = normalizeRecords(data || []);
    metricConfigs.value = resolveMetricConfigs(rawRecords.value);
    primaryMetric.value = resolvePrimaryMetric();
    metricCards.value = buildMetricCards();
    deviceStats.value = buildDeviceStats();
    coverageRatio.value = calculateCoverageRatio();
    if (!rawRecords.value.length || !metricConfigs.value.length || !primaryMetric.value) {
      return;
    }
    reportReady.value = true;
    nextTick(() => {
      renderAllCharts();
    });
  } catch (error) {
    ElMessage.error('多维报表加载失败，请稍后重试');
  } finally {
    loading.value = false;
  }
};

const buildRequestQuery = () => {
  const query = {
    samplingInterval: queryForm.value.samplingInterval,
    params: {
      beginRecordTime: daterangeRecordTime.value[0],
      endRecordTime: daterangeRecordTime.value[1]
    }
  };
  if (queryForm.value.monitorIds && queryForm.value.monitorIds.length > 1) {
    query.monitorIds = queryForm.value.monitorIds;
  } else {
    query.monitorId = queryForm.value.monitorIds[0] || queryForm.value.monitorId;
  }
  if (isVibrationSource.value) {
    query.vibrationParam = queryForm.value.vibrationParam;
  }
  return query;
};

const normalizeRecords = (records) => {
  return (records || [])
    .map((item) => ({
      monitorId: item.monitorId,
      recodeTime: item.recodeTime,
      temperature: toNumber(item.temperature),
      humidity: toNumber(item.humidity),
      noise: toNumber(item.noise),
      illuminance: toNumber(item.illuminance),
      concentration: toNumber(item.concentration),
      vibrationSpeed: toNumber(item.vibrationSpeed),
      vibrationDisplacement: toNumber(item.vibrationDisplacement),
      vibrationAcceleration: toNumber(item.vibrationAcceleration),
      vibrationTemp: toNumber(item.vibrationTemp)
    }))
    .sort((a, b) => new Date(a.recodeTime).getTime() - new Date(b.recodeTime).getTime());
};

const resolveMetricConfigs = (records) => {
  return getMetricCandidates()
    .map((field) => METRIC_DEFINITIONS[field])
    .filter((config) => records.some((record) => isValidValue(record[config.field])));
};

const getMetricCandidates = () => {
  if (isVibrationSource.value) {
    return [queryForm.value.vibrationParam, 'vibrationSpeed', 'vibrationDisplacement', 'vibrationAcceleration', 'vibrationTemp'].filter(
      (item, index, array) => array.indexOf(item) === index
    );
  }
  const metricTypeMap = {
    5: ['temperature'],
    6: ['temperature', 'humidity'],
    7: ['noise'],
    8: ['illuminance'],
    9: ['concentration']
  };
  const activeTypes = selectedEnergyTypes.value.length ? selectedEnergyTypes.value : parseMonitorTypes(queryForm.value.monitorType);
  const metrics = activeTypes.reduce((accumulator, type) => {
    return accumulator.concat(metricTypeMap[type] || []);
  }, []);
  return metrics.filter((item, index, array) => array.indexOf(item) === index);
};

const resolvePrimaryMetric = () => {
  if (!metricConfigs.value.length) {
    return null;
  }
  const preferredField =
    queryForm.value.primaryMetricField || (isVibrationSource.value ? queryForm.value.vibrationParam : metricConfigs.value[0].field);
  const matchedMetric = metricConfigs.value.find((item) => item.field === preferredField);
  const resolvedMetric = matchedMetric || metricConfigs.value[0];
  queryForm.value.primaryMetricField = resolvedMetric.field;
  return resolvedMetric;
};

const handlePrimaryMetricChange = () => {
  primaryMetric.value = resolvePrimaryMetric();
  if (!primaryMetric.value || !reportReady.value) {
    return;
  }
  deviceStats.value = buildDeviceStats();
  nextTick(() => {
    renderAllCharts();
  });
};

const renderAllCharts = () => {
  renderTrendChart();
  renderGaugeChart();
  renderSankeyChart();
  renderFunnelChart();
  renderLiquidChart();
  renderRadarChart();
  renderHourlyChart();
  if (hasMultiDevice.value) {
    renderDeviceRankChart();
    renderDeviceScatterChart();
  }
};

const buildMetricCards = () => {
  return metricConfigs.value.slice(0, 4).map((config) => {
    const stats = getMetricStats(config.field);
    return {
      ...config,
      latest: stats.latest,
      avg: stats.avg,
      max: stats.max
    };
  });
};

const buildDeviceStats = () => {
  if (!primaryMetric.value) {
    return [];
  }
  const field = primaryMetric.value.field;
  const deviceMap = {};
  rawRecords.value.forEach((item) => {
    if (!item.monitorId || !isValidValue(item[field])) {
      return;
    }
    if (!deviceMap[item.monitorId]) {
      deviceMap[item.monitorId] = [];
    }
    deviceMap[item.monitorId].push(item[field]);
  });
  return Object.keys(deviceMap)
    .map((monitorId) => {
      const values = deviceMap[monitorId];
      const sortedValues = [...values].sort((a, b) => a - b);
      return {
        monitorId,
        monitorName: getMonitorDisplayName(monitorId),
        latest: values[values.length - 1],
        avg: average(values),
        max: sortedValues[sortedValues.length - 1],
        count: values.length
      };
    })
    .sort((a, b) => b.avg - a.avg);
};

const calculateCoverageRatio = () => {
  if (!rawRecords.value.length || !metricConfigs.value.length) {
    return 0;
  }
  const totalPoints = rawRecords.value.length * metricConfigs.value.length;
  const validPoints = metricConfigs.value.reduce((sum, config) => sum + getMetricValues(config.field).length, 0);
  return totalPoints ? validPoints / totalPoints : 0;
};

const getMetricValues = (field, monitorId) => {
  return rawRecords.value
    .filter((item) => !monitorId || item.monitorId === monitorId)
    .map((item) => item[field])
    .filter((value) => isValidValue(value));
};

const getMetricStats = (field, monitorId) => {
  const values = getMetricValues(field, monitorId);
  if (!values.length) {
    return {
      latest: null,
      avg: null,
      max: null,
      p75: null,
      p90: null
    };
  }
  const sortedValues = [...values].sort((a, b) => a - b);
  return {
    latest: values[values.length - 1],
    avg: average(values),
    max: sortedValues[sortedValues.length - 1],
    p75: percentile(sortedValues, 0.75),
    p90: percentile(sortedValues, 0.9)
  };
};

const getBands = (values) => {
  const sortedValues = [...values].sort((a, b) => a - b);
  return {
    low: percentile(sortedValues, 0.33),
    high: percentile(sortedValues, 0.66),
    avg: average(sortedValues),
    p75: percentile(sortedValues, 0.75),
    p90: percentile(sortedValues, 0.9)
  };
};

const getBandLabel = (value, bands) => {
  if (value <= bands.low) {
    return '平稳';
  }
  if (value <= bands.high) {
    return '关注';
  }
  return '高位';
};

const renderTrendChart = () => {
  if (hasMultiDevice.value) {
    renderDeviceTrendChart();
    return;
  }
  const metrics = metricConfigs.value.slice(0, 3);
  setChartData('trendChart', {
    color: metrics.map((item) => item.color),
    tooltip: {
      trigger: 'axis'
    },
    legend: {
      top: 8,
      data: metrics.map((item) => item.label)
    },
    grid: {
      top: 54,
      left: '7%',
      right: '4%',
      bottom: 48
    },
    dataZoom: [
      {
        type: 'slider',
        height: 16
      }
    ],
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: rawRecords.value.map((item) => item.recodeTime)
    },
    yAxis: {
      type: 'value',
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
    },
    series: metrics.map((item) => ({
      name: item.label,
      type: 'line',
      smooth: true,
      connectNulls: true,
      showSymbol: false,
      areaStyle: {
        opacity: 0.08
      },
      data: rawRecords.value.map((record) => record[item.field])
    }))
  });
};

const renderDeviceTrendChart = () => {
  const topDevices = deviceStats.value.slice(0, 6);
  setChartData('trendChart', {
    tooltip: {
      trigger: 'axis'
    },
    legend: {
      top: 8,
      data: topDevices.map((item) => getShortDisplayName(item.monitorId))
    },
    grid: {
      top: 54,
      left: '7%',
      right: '4%',
      bottom: 48
    },
    dataZoom: [
      {
        type: 'slider',
        height: 16
      }
    ],
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: rawRecords.value.map((item) => item.recodeTime)
    },
    yAxis: {
      type: 'value',
      name: `${primaryMetric.value.label}(${primaryMetric.value.unit})`,
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
    },
    series: topDevices.map((item) => ({
      name: getShortDisplayName(item.monitorId),
      type: 'line',
      smooth: true,
      connectNulls: true,
      showSymbol: false,
      data: rawRecords.value.map((record) => (record.monitorId === item.monitorId ? record[primaryMetric.value.field] : null))
    }))
  });
};

const renderGaugeChart = () => {
  if (hasMultiDevice.value) {
    renderGroupGaugeChart();
    return;
  }
  const gaugeMetrics = metricConfigs.value.slice(0, 3);
  const centers = [
    ['18%', '55%'],
    ['50%', '55%'],
    ['82%', '55%']
  ];
  setChartData('gaugeChart', {
    series: gaugeMetrics.map((item, index) => {
      const stats = getMetricStats(item.field);
      const latest = stats.latest || 0;
      const maxValue = Math.max(1, ceilNumber((stats.max || latest || 1) * 1.15));
      return {
        type: 'gauge',
        min: 0,
        max: maxValue,
        radius: '78%',
        center: centers[index],
        progress: {
          show: true,
          width: 12,
          itemStyle: {
            color: item.color
          }
        },
        axisLine: {
          lineStyle: {
            width: 12
          }
        },
        pointer: {
          show: false
        },
        axisTick: {
          show: false
        },
        splitLine: {
          length: 10
        },
        axisLabel: {
          distance: 16,
          fontSize: 10
        },
        title: {
          offsetCenter: [0, '82%'],
          fontSize: 12
        },
        detail: {
          offsetCenter: [0, '22%'],
          fontSize: 18,
          formatter: (value) => `${formatValue(value)} ${item.unit}`
        },
        data: [
          {
            value: latest,
            name: item.label
          }
        ]
      };
    })
  });
};

const renderGroupGaugeChart = () => {
  const stats = getMetricStats(primaryMetric.value.field);
  const maxValue = Math.max(1, ceilNumber((stats.max || 1) * 1.15));
  const gaugeData = [
    {
      label: '群组均值',
      value: stats.avg || 0,
      center: ['20%', '55%']
    },
    {
      label: '群组峰值',
      value: stats.max || 0,
      center: ['50%', '55%']
    },
    {
      label: '最新均值',
      value: average(deviceStats.value.map((item) => item.latest)),
      center: ['80%', '55%']
    }
  ];
  setChartData('gaugeChart', {
    series: gaugeData.map((item, index) => ({
      type: 'gauge',
      min: 0,
      max: maxValue,
      radius: '78%',
      center: item.center,
      progress: {
        show: true,
        width: 12,
        itemStyle: {
          color: [primaryMetric.value.color, '#36cfc9', '#5b8ff9'][index]
        }
      },
      axisLine: {
        lineStyle: {
          width: 12
        }
      },
      pointer: {
        show: false
      },
      axisTick: {
        show: false
      },
      splitLine: {
        length: 10
      },
      axisLabel: {
        distance: 16,
        fontSize: 10
      },
      title: {
        offsetCenter: [0, '82%'],
        fontSize: 12
      },
      detail: {
        offsetCenter: [0, '22%'],
        fontSize: 18,
        formatter: (value) => `${formatValue(value)} ${primaryMetric.value.unit}`
      },
      data: [
        {
          value: item.value,
          name: item.label
        }
      ]
    }))
  });
};

const renderSankeyChart = () => {
  if (hasMultiDevice.value) {
    renderDeviceSankeyChart();
    return;
  }
  const nodes = [
    {
      name: '采样点'
    }
  ];
  const links = [];
  const stageNames = ['平稳', '关注', '高位'];
  metricConfigs.value.forEach((config) => {
    const values = getMetricValues(config.field);
    if (!values.length) {
      return;
    }
    const bands = getBands(values);
    const stageCounter = {
      平稳: 0,
      关注: 0,
      高位: 0
    };
    values.forEach((value) => {
      stageCounter[getBandLabel(value, bands)] += 1;
    });
    nodes.push({
      name: config.label
    });
    links.push({
      source: '采样点',
      target: config.label,
      value: values.length
    });
    stageNames.forEach((stage) => {
      links.push({
        source: config.label,
        target: stage,
        value: stageCounter[stage]
      });
    });
  });
  stageNames.forEach((stage) => {
    nodes.push({
      name: stage
    });
  });
  setChartData('sankeyChart', {
    tooltip: {
      trigger: 'item'
    },
    series: [
      {
        type: 'sankey',
        left: 12,
        right: 12,
        top: 16,
        bottom: 16,
        emphasis: {
          focus: 'adjacency'
        },
        lineStyle: {
          color: 'gradient',
          curveness: 0.5
        },
        data: nodes,
        links
      }
    ]
  });
};

const renderDeviceSankeyChart = () => {
  const bands = getBands(getMetricValues(primaryMetric.value.field));
  const stageNames = ['平稳', '关注', '高位'];
  const topDevices = deviceStats.value.slice(0, 10);
  const nodes = topDevices
    .map((item) => ({
      name: item.monitorName
    }))
    .concat(
      stageNames.map((stage) => ({
        name: stage
      }))
    );
  const links = topDevices.map((item) => ({
    source: item.monitorName,
    target: getBandLabel(item.avg, bands),
    value: item.count
  }));
  setChartData('sankeyChart', {
    tooltip: {
      trigger: 'item'
    },
    series: [
      {
        type: 'sankey',
        left: 12,
        right: 12,
        top: 16,
        bottom: 16,
        emphasis: {
          focus: 'adjacency'
        },
        lineStyle: {
          color: 'gradient',
          curveness: 0.5
        },
        data: deviceStats.value
          .slice(0, 10)
          .map((item) => ({
            name: item.monitorName
          }))
          .concat(
            stageNames.map((stage) => ({
              name: stage
            }))
          ),
        links
      }
    ]
  });
};

const renderFunnelChart = () => {
  if (hasMultiDevice.value) {
    renderDeviceFunnelChart();
    return;
  }
  const values = getMetricValues(primaryMetric.value.field);
  const bands = getBands(values);
  setChartData('funnelChart', {
    tooltip: {
      trigger: 'item',
      formatter: '{b}: {c}'
    },
    series: [
      {
        type: 'funnel',
        left: '12%',
        width: '76%',
        top: 18,
        bottom: 16,
        label: {
          show: true,
          position: 'inside'
        },
        data: [
          {
            name: '有效采样',
            value: values.length
          },
          {
            name: '高于均值',
            value: values.filter((item) => item >= bands.avg).length
          },
          {
            name: '进入P75',
            value: values.filter((item) => item >= bands.p75).length
          },
          {
            name: '进入P90',
            value: values.filter((item) => item >= bands.p90).length
          }
        ]
      }
    ]
  });
};

const renderDeviceFunnelChart = () => {
  const averages = deviceStats.value.map((item) => item.avg);
  const bands = getBands(averages);
  setChartData('funnelChart', {
    tooltip: {
      trigger: 'item',
      formatter: '{b}: {c}'
    },
    series: [
      {
        type: 'funnel',
        left: '12%',
        width: '76%',
        top: 18,
        bottom: 16,
        label: {
          show: true,
          position: 'inside'
        },
        data: [
          {
            name: '纳入对比设备',
            value: deviceStats.value.length
          },
          {
            name: '均值高于整体均值',
            value: deviceStats.value.filter((item) => item.avg >= bands.avg).length
          },
          {
            name: '进入设备P75',
            value: deviceStats.value.filter((item) => item.avg >= bands.p75).length
          },
          {
            name: '进入设备P90',
            value: deviceStats.value.filter((item) => item.avg >= bands.p90).length
          }
        ]
      }
    ]
  });
};

const renderLiquidChart = () => {
  const ratio = Number(coverageRatio.value.toFixed(4));
  setChartData('liquidChart', {
    series: [
      {
        type: 'liquidFill',
        radius: '74%',
        data: [ratio, Math.max(ratio - 0.08, 0), Math.max(ratio - 0.16, 0)],
        color: ['#36cfc9', '#13c2c2', '#08979c'],
        outline: {
          borderDistance: 4,
          itemStyle: {
            borderWidth: 3,
            borderColor: '#36cfc9'
          }
        },
        label: {
          formatter: `${formatPercent(ratio)}\n覆盖率`,
          fontSize: 20,
          color: '#135200'
        }
      }
    ]
  });
};

const renderRadarChart = () => {
  const metrics = metricConfigs.value.slice(0, 5);
  const indicator = metrics.map((item) => ({
    name: item.label,
    max: 100
  }));
  const compareA = [];
  const compareB = [];
  metrics.forEach((item) => {
    const stats = getMetricStats(item.field);
    compareA.push(normalizePercent(hasMultiDevice.value ? stats.avg : stats.latest, stats.max));
    compareB.push(normalizePercent(stats.max, stats.max));
  });
  setChartData('radarChart', {
    legend: {
      bottom: 0,
      data: [hasMultiDevice.value ? '群组均值' : '最新值', '峰值上限']
    },
    radar: {
      radius: '60%',
      indicator,
      splitArea: {
        areaStyle: {
          color: ['rgba(91,143,249,0.08)', 'rgba(91,143,249,0.14)']
        }
      }
    },
    series: [
      {
        type: 'radar',
        data: [
          {
            name: hasMultiDevice.value ? '群组均值' : '最新值',
            value: compareA,
            areaStyle: {
              opacity: 0.18
            }
          },
          {
            name: '峰值上限',
            value: compareB,
            areaStyle: {
              opacity: 0.08
            }
          }
        ]
      }
    ]
  });
};

const renderHourlyChart = () => {
  const field = primaryMetric.value.field;
  const hourMap = {};
  rawRecords.value.forEach((item) => {
    if (!isValidValue(item[field]) || !item.recodeTime) {
      return;
    }
    const hour = item.recodeTime.slice(11, 13);
    if (!hourMap[hour]) {
      hourMap[hour] = [];
    }
    hourMap[hour].push(item[field]);
  });
  const hours = Object.keys(hourMap).sort();
  setChartData('hourlyChart', {
    color: [primaryMetric.value.color],
    tooltip: {
      trigger: 'axis'
    },
    grid: {
      top: 20,
      left: '9%',
      right: '4%',
      bottom: 36
    },
    xAxis: {
      type: 'category',
      data: hours
    },
    yAxis: {
      type: 'value',
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
    },
    series: [
      {
        type: 'bar',
        barWidth: 18,
        data: hours.map((hour) => average(hourMap[hour])),
        itemStyle: {
          borderRadius: [6, 6, 0, 0]
        }
      }
    ]
  });
};

const renderDeviceRankChart = () => {
  const topDevices = deviceStats.value.slice(0, 10);
  setChartData('deviceRankChart', {
    tooltip: {
      trigger: 'axis'
    },
    legend: {
      top: 8,
      data: ['均值', '最新值']
    },
    grid: {
      top: 56,
      left: '12%',
      right: '6%',
      bottom: 36
    },
    xAxis: {
      type: 'value'
    },
    yAxis: {
      type: 'category',
      data: topDevices.map((item) => getShortDisplayName(item.monitorId))
    },
    series: [
      {
        name: '均值',
        type: 'bar',
        data: topDevices.map((item) => item.avg),
        itemStyle: {
          color: primaryMetric.value.color
        }
      },
      {
        name: '最新值',
        type: 'bar',
        data: topDevices.map((item) => item.latest),
        itemStyle: {
          color: '#36cfc9'
        }
      }
    ]
  });
};

const renderDeviceScatterChart = () => {
  setChartData('deviceScatterChart', {
    tooltip: {
      formatter: (params) => {
        const value = params.value;
        return [
          `设备: ${value[3]}`,
          `编码: ${value[4]}`,
          `均值: ${formatValue(value[0])}${primaryMetric.value.unit}`,
          `峰值: ${formatValue(value[1])}${primaryMetric.value.unit}`,
          `采样量: ${value[2]}`
        ].join('<br/>');
      }
    },
    xAxis: {
      type: 'value',
      name: `均值(${primaryMetric.value.unit})`,
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
    },
    yAxis: {
      type: 'value',
      name: `峰值(${primaryMetric.value.unit})`,
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
    },
    series: [
      {
        type: 'scatter',
        symbolSize: (value) => Math.max(12, Math.min(30, value[2] * 2)),
        itemStyle: {
          color: primaryMetric.value.color,
          opacity: 0.8
        },
        label: {
          show: true,
          formatter: (params) => params.value[3],
          position: 'top',
          fontSize: 11
        },
        data: deviceStats.value.slice(0, 12).map((item) => [item.avg, item.max, item.count, getShortDisplayName(item.monitorId), item.monitorId])
      }
    ]
  });
};

const setChartData = (refName, option) => {
  chartRefMap[refName]?.value?.setData(option);
};

const goBack = () => {
  proxy?.$router.back();
};

const getMonitorDisplayName = (monitorId) => {
  if (!monitorId) {
    return '--';
  }
  const cachedItem = deviceDisplayMap.value[monitorId];
  return cachedItem && cachedItem.label ? cachedItem.label : monitorId;
};

const getShortDisplayName = (monitorId) => {
  const displayName = getMonitorDisplayName(monitorId);
  if (displayName.length <= 10) {
    return displayName;
  }
  return `${displayName.slice(0, 9)}...`;
};

const toNumber = (value) => {
  if (value === null || value === undefined || value === '') {
    return null;
  }
  const parsedValue = Number(value);
  return Number.isNaN(parsedValue) ? null : parsedValue;
};

const isValidValue = (value) => {
  return value !== null && value !== undefined && !Number.isNaN(value);
};

const average = (values) => {
  if (!values || !values.length) {
    return 0;
  }
  return values.reduce((sum, item) => sum + item, 0) / values.length;
};

const percentile = (sortedValues, ratio) => {
  if (!sortedValues || !sortedValues.length) {
    return 0;
  }
  const index = Math.min(sortedValues.length - 1, Math.max(0, Math.ceil(sortedValues.length * ratio) - 1));
  return sortedValues[index];
};

const normalizePercent = (value, max) => {
  if (!isValidValue(value) || !isValidValue(max) || max <= 0) {
    return 0;
  }
  return Number(((value / max) * 100).toFixed(2));
};

const ceilNumber = (value) => {
  return Math.ceil(value * 10) / 10;
};

const formatValue = (value) => {
  if (!isValidValue(value)) {
    return '--';
  }
  return Number(value).toFixed(2);
};

const formatPercent = (value) => {
  return `${(Number(value || 0) * 100).toFixed(1)}%`;
};

onMounted(() => {
  initializeReport();
});
</script>

<style scoped>
.report-page {
  min-height: calc(100vh - 84px);
  background: linear-gradient(180deg, #f3f8ff 0%, #f7f8fa 100%);
}

.hero-card {
  margin-bottom: 16px;
  border: 1px solid #d6e4ff;
  border-radius: 18px;
  background: linear-gradient(135deg, #ffffff 0%, #eef5ff 100%);
}

.selector-card {
  margin-bottom: 16px;
  border-radius: 18px;
  border: 1px solid #e7ecf3;
}

.hero-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  margin-bottom: 16px;
}

.hero-title {
  font-size: 24px;
  line-height: 1.2;
  font-weight: 700;
  color: #1f2329;
}

.hero-desc {
  margin-top: 8px;
  font-size: 13px;
  color: #5b6573;
}

.selector-head {
  margin-bottom: 14px;
}

.selector-title {
  font-size: 18px;
  font-weight: 700;
  color: #1f2329;
}

.selector-desc {
  margin-top: 6px;
  font-size: 13px;
  color: #5b6573;
}

.energy-toolbar {
  margin-bottom: 12px;
}

.energy-count {
  margin-left: 2px;
  color: #86909c;
}

.selector-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.tree-panel {
  max-height: 280px;
  overflow: auto;
  padding: 12px 10px;
  border-radius: 14px;
  background: linear-gradient(180deg, #fafcff 0%, #f5f8ff 100%);
}

.query-form {
  margin-bottom: -12px;
}

.form-suffix {
  margin-left: 6px;
  color: #909399;
}

.overview-grid,
.metric-grid,
.chart-grid {
  display: grid;
  gap: 16px;
  margin-bottom: 16px;
}

.overview-grid {
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

.metric-grid {
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.chart-grid.two-col {
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
}

.chart-grid.three-col {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.overview-card,
.metric-card {
  min-height: 126px;
  padding: 18px 20px;
  border-radius: 18px;
  background: #ffffff;
  box-shadow: 0 10px 24px rgba(31, 35, 41, 0.06);
}

.overview-label,
.metric-name {
  color: #5b6573;
  font-size: 13px;
}

.overview-value,
.metric-value {
  margin-top: 14px;
  font-size: 28px;
  font-weight: 700;
  line-height: 1.1;
  color: #1f2329;
}

.overview-text {
  font-size: 20px;
  line-height: 1.35;
  word-break: break-word;
}

.overview-foot,
.metric-foot {
  margin-top: 10px;
  font-size: 12px;
  color: #86909c;
}

.metric-card {
  border-top: 4px solid #5b8ff9;
}

.metric-value span {
  margin-left: 4px;
  font-size: 14px;
  font-weight: 500;
}

.chart-card {
  min-width: 0;
  border: none;
  border-radius: 18px;
  box-shadow: 0 10px 24px rgba(31, 35, 41, 0.06);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  color: #1f2329;
  font-weight: 600;
}

.card-tip {
  font-size: 12px;
  font-weight: 400;
  color: #86909c;
}

.chart {
  width: 100%;
  min-width: 0;
  height: clamp(320px, 40vh, 460px);
}

.chart-lg {
  height: clamp(340px, 44vh, 500px);
}

.chart-sm {
  height: clamp(280px, 34vh, 360px);
}

.empty-panel {
  padding: 88px 24px;
  border-radius: 18px;
  background: #ffffff;
  text-align: center;
  color: #86909c;
  box-shadow: 0 10px 24px rgba(31, 35, 41, 0.06);
}

.empty-icon {
  display: inline-block;
  margin-bottom: 16px;
  font-size: 44px;
  color: #91a4ff;
}

@media screen and (max-width: 992px) {
  .hero-head,
  .card-header {
    display: block;
  }

  .card-tip {
    display: block;
    margin-top: 6px;
  }
}

@media screen and (max-width: 768px) {
  .chart-grid.two-col,
  .chart-grid.three-col {
    grid-template-columns: 1fr;
  }

  .hero-actions {
    margin-top: 12px;
  }

  .selector-summary {
    display: block;
  }
}
</style>
