<template>
  <div class="p-2 trend-report-page">
    <el-row :gutter="12">
      <el-col :xs="24" :md="7" :lg="6">
        <el-card shadow="hover" class="side-card">
          <el-form label-position="top">
            <el-form-item label="设备类型">
              <el-select v-model="deviceType" class="w-full" @change="handleDeviceTypeChange">
                <el-option v-for="dict in device_type" :key="dict.value" :label="dict.label" :value="dict.value" />
              </el-select>
            </el-form-item>
          </el-form>
          <el-tree
            ref="deviceTreeRef"
            class="device-tree"
            :data="deviceTree"
            node-key="deviceId"
            show-checkbox
            default-expand-all
            check-strictly
            :props="{ label: 'name', children: 'children', disabled: 'disabled' }"
          />
        </el-card>
      </el-col>

      <el-col :xs="24" :md="17" :lg="18">
        <el-card shadow="hover" class="filter-card">
          <el-form :inline="true">
            <el-form-item label="打点间隔">
              <el-select v-model="interval" class="interval-select">
                <el-option label="1分钟" :value="1" />
                <el-option label="5分钟" :value="5" />
                <el-option label="15分钟" :value="15" />
                <el-option label="30分钟" :value="30" />
                <el-option label="60分钟" :value="60" />
              </el-select>
            </el-form-item>
            <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="结束时间"
                :default-time="defaultTime"
              />
            </el-form-item>
            <el-form-item label="类型">
              <el-select v-model="aggregateType" class="aggregate-select">
                <el-option label="最大值" value="max" />
                <el-option label="最小值" value="min" />
                <el-option label="平均值" value="avg" />
                <el-option label="相加" value="sum" />
                <el-option label="相减" value="subtract" />
                <el-option label="最新值" value="latest" />
                <el-option label="正差值" value="positive_diff" />
                <el-option label="负差值" value="negative_diff" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="loadReport">查询</el-button>
              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
            </el-form-item>
          </el-form>
        </el-card>

        <el-card shadow="hover" class="chart-card">
          <div v-loading="loading" class="chart-wrap">
            <div ref="chartRef" class="chart"></div>
            <el-empty v-if="!loading && empty" class="chart-empty" description="暂无趋势数据" />
          </div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup name="TrendReport" lang="ts">
import * as echarts from 'echarts';
import { getTrendReport } from '@/api/report';
import { listFloorInfo } from '@/api/system/floor';
import { FloorInfoVO } from '@/api/system/floor/types';

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { device_type } = toRefs<any>(proxy?.useDict('device_type'));

const deviceTreeRef = ref();
const chartRef = ref<HTMLDivElement>();
let chart: echarts.ECharts | undefined;

const deviceType = ref<string | number>('2');
const deviceTree = ref<any[]>([]);
const interval = ref(5);
type AggregateType = 'max' | 'min' | 'avg' | 'sum' | 'subtract' | 'latest' | 'positive_diff' | 'negative_diff';
const aggregateType = ref<AggregateType>('avg');
const timeRange = ref<string[]>([]);
const loading = ref(false);
const empty = ref(true);
const valueName = ref('用电量');
const unit = ref('kWh');
const defaultTime: [Date, Date] = [new Date(2000, 0, 1, 0, 0, 0), new Date(2000, 0, 1, 23, 59, 59)];

function pad(value: number) {
  return String(value).padStart(2, '0');
}

function formatDateTime(date: Date) {
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
}

function initDefaultRange() {
  const end = new Date();
  const start = new Date(end.getTime() - 24 * 60 * 60 * 1000);
  timeRange.value = [formatDateTime(start), formatDateTime(end)];
}

function normalizeDeviceTree(rows: FloorInfoVO[]): any[] {
  return rows
    .map((row) => {
      const children = normalizeDeviceTree(row.children || []);
      if (row.isDevice === '1') {
        if (String(row.deviceType || '') !== String(deviceType.value)) return null;
        return {
          id: row.id,
          nodeKey: String(row.id),
          deviceId: row.deviceId,
          name: row.name || row.deviceId,
          isDevice: row.isDevice,
          disabled: false,
          children: []
        };
      }
      if (!children.length) return null;
      return {
        id: row.id,
        nodeKey: `node_${row.id}`,
        name: row.name,
        isDeviceGroup: row.isDeviceGroup,
        disabled: row.isDeviceGroup !== '1',
        children
      };
    })
    .filter(Boolean);
}

function collectDeviceIds(node: any): string[] {
  if (!node) return [];
  if (node.isDevice === '1' && node.deviceId) return [String(node.deviceId)];
  return (node.children || []).flatMap((child: any) => collectDeviceIds(child));
}

async function loadTree() {
  const res = await listFloorInfo();
  deviceTree.value = normalizeDeviceTree((res as any).rows || []);
}

function initChart() {
  if (chartRef.value && !chart) chart = echarts.init(chartRef.value, 'macarons');
}

function renderChart(data: any) {
  initChart();
  empty.value = !(data.series || []).some((item: any) => (item.data || []).some((value: number | null) => value !== null));
  chart?.setOption(
    {
      tooltip: { trigger: 'axis', valueFormatter: (value: unknown) => `${Number(value || 0).toFixed(2)} ${unit.value}` },
      legend: { type: 'scroll', top: 0 },
      grid: { top: 54, left: 54, right: 24, bottom: 42 },
      xAxis: { type: 'category', data: data.xAxis || [] },
      yAxis: { type: 'value', name: `${valueName.value}(${unit.value})` },
      series: data.series || []
    },
    true
  );
}

async function loadReport() {
  const checked = (deviceTreeRef.value?.getCheckedNodes?.() || []).filter((node: any) => !node.disabled);
  const deviceIds = [...new Set(checked.flatMap((node: any) => collectDeviceIds(node)))];
  if (!deviceIds.length || !timeRange.value.length) {
    renderChart({ xAxis: [], series: [] });
    return;
  }
  loading.value = true;
  try {
    const res = await getTrendReport({
      deviceType: deviceType.value,
      deviceIds: deviceIds.join(','),
      interval: interval.value,
      beginTime: timeRange.value[0],
      endTime: timeRange.value[1],
      aggregateType: aggregateType.value
    });
    valueName.value = res.data.valueName;
    unit.value = res.data.unit;
    renderChart(res.data);
  } finally {
    loading.value = false;
  }
}

async function handleDeviceTypeChange() {
  deviceTreeRef.value?.setCheckedKeys?.([]);
  await loadTree();
}

async function resetQuery() {
  interval.value = 5;
  aggregateType.value = 'avg';
  initDefaultRange();
  await loadReport();
}

function resizeChart() {
  chart?.resize();
}

onMounted(async () => {
  initDefaultRange();
  await loadTree();
  await nextTick();
  initChart();
  window.addEventListener('resize', resizeChart);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', resizeChart);
  chart?.dispose();
  chart = undefined;
});
</script>

<style scoped>
.side-card,
.filter-card,
.chart-card {
  margin-bottom: 12px;
}

.device-tree {
  max-height: 640px;
  overflow: auto;
}

.interval-select,
.aggregate-select {
  width: 110px;
}

.chart-wrap {
  position: relative;
  min-height: 560px;
}

.chart {
  width: 100%;
  height: 560px;
}

.chart-empty {
  position: absolute;
  inset: 80px 0 0;
  pointer-events: none;
}
</style>
