<template>
  <div class="report-page p-2">
    <el-card shadow="never" class="hero-card">
      <div class="hero-grid">
        <div class="hero-main">
          <div class="hero-kicker">IOT PERIOD REPORT</div>
          <div class="hero-title">物联周期报表中心</div>
          <div class="hero-desc">统一小时报、日报、周报、月报统计口径，直接复用动态分表数据源，避免历史查询、导出、报表三条链路各算各的。</div>
          <div class="hero-tags">
            <el-tag effect="dark" round class="hero-tag">{{ currentPeriodLabel }}</el-tag>
            <el-tag effect="plain" round class="hero-tag">{{ selectedMonitorLabel }}</el-tag>
            <el-tag effect="plain" round class="hero-tag">{{ activeMetricLabel }}</el-tag>
          </div>
        </div>
        <div class="hero-side">
          <div class="hero-panel">
            <div class="hero-panel-label">当前窗口</div>
            <div class="hero-panel-value">{{ currentRangeShortLabel }}</div>
            <div class="hero-panel-foot">默认支持从曲线页或看板页带参进入，无需二次选择上下文。</div>
          </div>
        </div>
      </div>
    </el-card>

    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div v-show="showSearch" class="mb-[10px]">
        <el-card shadow="hover" class="query-card">
          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="88px">
            <el-form-item label="点位名称" prop="monitorCode">
              <el-tree-select
                v-model="queryParams.monitorCode"
                :data="monitorTreeOptions"
                :props="monitorTreeProps"
                placeholder="请选择点位"
                clearable
                filterable
                check-strictly
                style="width: 240px"
              />
            </el-form-item>
            <el-form-item label="测量项" prop="metricCode">
              <el-select v-model="queryParams.metricCode" placeholder="全部测量项" clearable filterable style="width: 180px">
                <el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
            <el-form-item label="统计周期" prop="periodType">
              <el-select v-model="queryParams.periodType" style="width: 160px">
                <el-option v-for="item in periodTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
            <el-form-item label="统计时间">
              <el-date-picker
                v-model="daterangePeriodTime"
                type="datetimerange"
                value-format="YYYY-MM-DD HH:mm:ss"
                range-separator="-"
                start-placeholder="开始时间"
                end-placeholder="结束时间"
                style="width: 360px"
              />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">查询报表</el-button>
              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
              <el-button type="warning" plain icon="Download" @click="handleExport">导出报表</el-button>
            </el-form-item>
          </el-form>
        </el-card>
      </div>
    </transition>

    <div class="summary-grid">
      <el-card shadow="never" class="summary-card">
        <div class="summary-label">统计周期</div>
        <div class="summary-value">{{ currentPeriodLabel }}</div>
        <div class="summary-foot">{{ currentRangeLabel }}</div>
      </el-card>
      <el-card shadow="never" class="summary-card">
        <div class="summary-label">报表行数</div>
        <div class="summary-value">{{ total }}</div>
        <div class="summary-foot">当前筛选条件下的聚合结果数</div>
      </el-card>
      <el-card shadow="never" class="summary-card">
        <div class="summary-label">报警总次数</div>
        <div class="summary-value">{{ totalAlarmCount }}</div>
        <div class="summary-foot">按周期窗口累计的告警条数</div>
      </el-card>
      <el-card shadow="never" class="summary-card">
        <div class="summary-label">最大样本数</div>
        <div class="summary-value">{{ maxSampleCount }}</div>
        <div class="summary-foot">单个周期窗口内的最大采样量</div>
      </el-card>
    </div>

    <el-card shadow="never" class="table-card">
      <template #header>
        <div class="card-header">
          <div>
            <div class="card-title">物联周期报表</div>
            <div class="card-subtitle">基于动态分表实时聚合，统一输出小时、日、周、月统计口径</div>
            <div class="card-tags">
              <span class="card-tag-item">点位：{{ selectedMonitorLabel }}</span>
              <span class="card-tag-item">测量项：{{ activeMetricLabel }}</span>
              <span class="card-tag-item">时间：{{ currentRangeShortLabel }}</span>
            </div>
          </div>
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
        </div>
      </template>

      <el-table v-loading="loading" border :data="reportRows" class="report-table">
        <el-table-column label="序号" type="index" width="60" align="center">
          <template #default="scope">
            {{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}
          </template>
        </el-table-column>
        <el-table-column label="点位名称" prop="monitorName" min-width="180" show-overflow-tooltip>
          <template #default="scope">
            <div class="main-cell">{{ resolveMonitorName(scope.row) }}</div>
            <div class="sub-cell">{{ scope.row.monitorCode || '-' }}</div>
          </template>
        </el-table-column>
        <el-table-column label="测量项" min-width="150" show-overflow-tooltip>
          <template #default="scope">
            <div class="main-cell">{{ scope.row.metricName || resolveMetricName(scope.row.metricCode) }}</div>
            <div class="sub-cell">{{ scope.row.metricCode || '-' }}</div>
          </template>
        </el-table-column>
        <el-table-column label="周期" align="center" width="100" prop="periodType">
          <template #default="scope">
            <el-tag size="small" effect="plain">{{ resolvePeriodTypeLabel(scope.row.periodType) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="周期开始" align="center" min-width="170">
          <template #default="scope">
            {{ formatDateTime(scope.row.periodStart) }}
          </template>
        </el-table-column>
        <el-table-column label="周期结束" align="center" min-width="170">
          <template #default="scope">
            {{ formatDateTime(scope.row.periodEnd) }}
          </template>
        </el-table-column>
        <el-table-column label="起始值" align="right" min-width="110">
          <template #default="scope">
            {{ formatNumber(scope.row.beginValue) }}
          </template>
        </el-table-column>
        <el-table-column label="结束值" align="right" min-width="110">
          <template #default="scope">
            {{ formatNumber(scope.row.endValue) }}
          </template>
        </el-table-column>
        <el-table-column label="平均值" align="right" min-width="110">
          <template #default="scope">
            {{ formatNumber(scope.row.avgValue) }}
          </template>
        </el-table-column>
        <el-table-column label="最大值" align="right" min-width="110">
          <template #default="scope">
            {{ formatNumber(scope.row.maxValue) }}
          </template>
        </el-table-column>
        <el-table-column label="最小值" align="right" min-width="110">
          <template #default="scope">
            {{ formatNumber(scope.row.minValue) }}
          </template>
        </el-table-column>
        <el-table-column label="增量" align="right" min-width="110">
          <template #default="scope">
            {{ formatNumber(scope.row.consumeValue) }}
          </template>
        </el-table-column>
        <el-table-column label="告警次数" align="center" min-width="100" prop="alarmCount" />
        <el-table-column label="样本数" align="center" min-width="100" prop="sampleCount" />
      </el-table>

      <div v-if="!loading && reportRows.length === 0" class="empty-panel">
        <div class="empty-icon">01</div>
        <div class="empty-title">当前筛选条件下没有可展示的周期报表</div>
        <div class="empty-desc">可以尝试放宽时间范围、切换统计周期，或者从点位树中改选其他设备后重新查询。</div>
      </div>

      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>
  </div>
</template>

<script setup name="ReportPeriodSummary" lang="ts">
import { getCurrentInstance } from 'vue';
import { useRoute } from 'vue-router';
import { getMonitorInfoTree } from '@/api/ems/base/baseMonitorInfo';
import { listAggregateReportPeriodSummary } from '@/api/ems/base/reportPeriodSummary';
import type { ReportPeriodSummaryQuery, ReportPeriodSummaryVO } from '@/api/ems/base/reportPeriodSummary/types';
import type { EmsTreeNode } from '@/api/ems/types';
import { parseTime } from '@/utils/ruoyi';

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute();

interface ReportTreeNode extends EmsTreeNode {
  label?: string;
  value?: string | number;
  children?: ReportTreeNode[];
}

interface MetricOption {
  label: string;
  value: string;
}

interface PeriodTypeOption {
  label: string;
  value: string;
}

const periodTypeOptions: PeriodTypeOption[] = [
  { label: '小时报', value: 'HOUR' },
  { label: '日报', value: 'DAY' },
  { label: '周报', value: 'WEEK' },
  { label: '月报', value: 'MONTH' }
];

const metricOptions: MetricOption[] = [
  { label: '温度', value: 'temperature' },
  { label: '湿度', value: 'humidity' },
  { label: '照度', value: 'illuminance' },
  { label: '噪声', value: 'noise' },
  { label: '气体浓度', value: 'concentration' },
  { label: '振动速度', value: 'vibrationSpeed' },
  { label: '振动位移', value: 'vibrationDisplacement' },
  { label: '振动加速度', value: 'vibrationAcceleration' },
  { label: '振动温度', value: 'vibrationTemp' }
];

const monitorTreeOptions = ref<ReportTreeNode[]>([]);
const monitorNameMap = ref<Record<string, string>>({});
const loading = ref(false);
const showSearch = ref(true);
const total = ref(0);
const reportRows = ref<ReportPeriodSummaryVO[]>([]);
const daterangePeriodTime = ref<string[]>([]);

const queryFormRef = ref<ElFormInstance>();

const monitorTreeProps = {
  label: 'label',
  value: 'value',
  children: 'children'
};

const queryParams = reactive<ReportPeriodSummaryQuery>({
  pageNum: 1,
  pageSize: 10,
  monitorCode: undefined,
  metricCode: undefined,
  periodType: 'DAY',
  periodStart: undefined,
  periodEnd: undefined,
  params: {}
});

const currentPeriodLabel = computed(() => resolvePeriodTypeLabel(queryParams.periodType));

const currentRangeLabel = computed(() => {
  if (!daterangePeriodTime.value?.length) {
    return '请选择统计时间范围';
  }
  return `${daterangePeriodTime.value[0]} 至 ${daterangePeriodTime.value[1]}`;
});

const currentRangeShortLabel = computed(() => {
  if (!daterangePeriodTime.value?.length) {
    return '未设置时间窗口';
  }
  return `${daterangePeriodTime.value[0]} ~ ${daterangePeriodTime.value[1]}`;
});

const selectedMonitorLabel = computed(() => {
  if (!queryParams.monitorCode) {
    return '全部物联点位';
  }
  return monitorNameMap.value[String(queryParams.monitorCode)] || String(queryParams.monitorCode);
});

const activeMetricLabel = computed(() => {
  if (!queryParams.metricCode) {
    return '全部测量项';
  }
  return resolveMetricName(String(queryParams.metricCode));
});

const totalAlarmCount = computed(() => reportRows.value.reduce((sum, item) => sum + Number(item.alarmCount || 0), 0));

const maxSampleCount = computed(() => reportRows.value.reduce((max, item) => Math.max(max, Number(item.sampleCount || 0)), 0));

const normalizeMonitorTree = (nodes: ReportTreeNode[] = []): ReportTreeNode[] =>
  nodes.map((node) => {
    const children = Array.isArray(node.children) ? normalizeMonitorTree(node.children) : [];
    const label = node.monitorName || node.label || node.name || node.monitorCode || String(node.value ?? '');
    const value = node.monitorCode || node.value || node.monitorId || node.objId || node.id;

    return {
      ...node,
      label,
      value,
      children
    };
  });

const collectMonitorNames = (nodes: ReportTreeNode[] = []) => {
  nodes.forEach((node) => {
    const key = String(node.value ?? node.monitorCode ?? '');
    if (key) {
      monitorNameMap.value[key] = node.label || node.monitorName || key;
    }
    if (node.children?.length) {
      collectMonitorNames(node.children);
    }
  });
};

const syncTimeRangeToQuery = () => {
  queryParams.periodStart = daterangePeriodTime.value?.[0];
  queryParams.periodEnd = daterangePeriodTime.value?.[1];
};

const initQueryFromRoute = () => {
  const beginRecordTime = route.query.beginRecordTime as string | undefined;
  const endRecordTime = route.query.endRecordTime as string | undefined;
  if (beginRecordTime && endRecordTime) {
    daterangePeriodTime.value = [beginRecordTime, endRecordTime];
  } else if (!daterangePeriodTime.value.length) {
    // 默认给近 24 小时，是为了让第一次进入页面就有可读结果，不需要用户再补一次时间。
    const end = new Date();
    const begin = new Date(end.getTime() - 24 * 60 * 60 * 1000);
    daterangePeriodTime.value = [parseTime(begin, '{y}-{m}-{d} {h}:{i}:{s}'), parseTime(end, '{y}-{m}-{d} {h}:{i}:{s}')];
  }

  if (typeof route.query.monitorId === 'string' && route.query.monitorId) {
    queryParams.monitorCode = route.query.monitorId;
  }
  if (typeof route.query.periodType === 'string' && route.query.periodType) {
    queryParams.periodType = route.query.periodType.toUpperCase();
  }
  if (typeof route.query.metricCode === 'string' && route.query.metricCode) {
    queryParams.metricCode = route.query.metricCode;
  }
  syncTimeRangeToQuery();
};

const loadMonitorTree = async () => {
  const response = await getMonitorInfoTree({
    monitorTypeList: [5, 6, 7, 8, 9, 10]
  } as any);
  monitorTreeOptions.value = normalizeMonitorTree(response.data || []);
  collectMonitorNames(monitorTreeOptions.value);
};

/** 查询周期报表 */
const getList = async () => {
  syncTimeRangeToQuery();
  if (!queryParams.periodStart || !queryParams.periodEnd) {
    proxy?.$modal.msgWarning('请选择完整的统计时间范围');
    return;
  }
  loading.value = true;
  try {
    const res = await listAggregateReportPeriodSummary(queryParams);
    reportRows.value = res.rows || [];
    total.value = Number(res.total || 0);
  } finally {
    loading.value = false;
  }
};

/** 搜索按钮操作 */
const handleQuery = () => {
  queryParams.pageNum = 1;
  getList();
};

/** 重置按钮操作 */
const resetQuery = () => {
  queryFormRef.value?.resetFields();
  queryParams.monitorCode = undefined;
  queryParams.metricCode = undefined;
  queryParams.periodType = 'DAY';
  initQueryFromRoute();
  handleQuery();
};

/** 导出按钮操作 */
const handleExport = () => {
  syncTimeRangeToQuery();
  if (!queryParams.periodStart || !queryParams.periodEnd) {
    proxy?.$modal.msgWarning('请选择完整的统计时间范围');
    return;
  }
  proxy?.download(
    'ems/base/reportPeriodSummary/aggregateExport',
    {
      ...queryParams
    },
    `iot_period_report_${new Date().getTime()}.xlsx`
  );
};

const resolveMonitorName = (row: ReportPeriodSummaryVO) =>
  row.monitorName || monitorNameMap.value[String(row.monitorCode || '')] || row.monitorCode || '-';

const resolveMetricName = (metricCode?: string) => metricOptions.find((item) => item.value === metricCode)?.label || metricCode || '-';

const resolvePeriodTypeLabel = (periodType?: string) => periodTypeOptions.find((item) => item.value === periodType)?.label || periodType || '-';

const formatDateTime = (value?: string | number | Date) => {
  if (!value) {
    return '-';
  }
  return parseTime(value as any, '{y}-{m}-{d} {h}:{i}:{s}');
};

const formatNumber = (value?: string | number) => {
  if (value === null || value === undefined || value === '') {
    return '-';
  }
  const numericValue = Number(value);
  if (Number.isNaN(numericValue)) {
    return value;
  }
  return numericValue.toFixed(2);
};

onMounted(async () => {
  initQueryFromRoute();
  await loadMonitorTree();
  await getList();
});
</script>

<style scoped lang="scss">
.report-page {
  --report-accent: #c46b23;
  --report-deep: #184a45;
  --report-soft: #f8efe4;
  --report-surface: #fffdfa;

  background:
    radial-gradient(circle at top left, rgba(196, 107, 35, 0.08), transparent 28%), linear-gradient(180deg, #fff9f2 0%, #f7f8f6 48%, #f3f5f3 100%);
  min-height: 100%;

  .hero-card {
    background:
      linear-gradient(135deg, rgba(24, 74, 69, 0.97), rgba(27, 89, 71, 0.92)), linear-gradient(45deg, rgba(196, 107, 35, 0.18), transparent 40%);
    border: none;
    border-radius: 22px;
    color: #f5efe6;
    margin-bottom: 12px;
    overflow: hidden;
    position: relative;
  }

  .hero-card::after {
    background: radial-gradient(circle at center, rgba(255, 255, 255, 0.16), transparent 60%);
    content: '';
    inset: -30% auto auto 60%;
    pointer-events: none;
    position: absolute;
    width: 360px;
    height: 360px;
  }

  .hero-grid {
    align-items: stretch;
    display: grid;
    gap: 18px;
    grid-template-columns: minmax(0, 2fr) minmax(280px, 0.95fr);
    position: relative;
    z-index: 1;
  }

  .hero-main {
    padding: 8px 4px 4px;
  }

  .hero-kicker {
    color: rgba(255, 240, 219, 0.72);
    font-size: 12px;
    letter-spacing: 0.22em;
    margin-bottom: 10px;
  }

  .hero-title {
    color: #fff8ef;
    font-size: 30px;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.15;
  }

  .hero-desc {
    color: rgba(255, 245, 234, 0.86);
    font-size: 14px;
    line-height: 1.8;
    margin-top: 12px;
    max-width: 760px;
  }

  .hero-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 18px;
  }

  .hero-tag {
    border-radius: 999px;
    padding: 0 10px;
  }

  .hero-side {
    display: flex;
    align-items: stretch;
    justify-content: flex-end;
  }

  .hero-panel {
    background: linear-gradient(180deg, rgba(255, 248, 239, 0.14), rgba(255, 248, 239, 0.06));
    backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 239, 220, 0.16);
    border-radius: 18px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 100%;
    padding: 20px 22px;
    width: 100%;
  }

  .hero-panel-label {
    color: rgba(255, 241, 221, 0.72);
    font-size: 12px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
  }

  .hero-panel-value {
    color: #fffaf3;
    font-size: 22px;
    font-weight: 600;
    line-height: 1.4;
    margin-top: 12px;
  }

  .hero-panel-foot {
    color: rgba(255, 241, 221, 0.76);
    font-size: 13px;
    line-height: 1.7;
    margin-top: 10px;
  }

  .query-card {
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(255, 250, 244, 0.96));
    border-radius: 18px;
    border: 1px solid rgba(196, 107, 35, 0.08);
    box-shadow: 0 16px 32px rgba(24, 74, 69, 0.05);
  }

  .summary-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 12px;
    margin-bottom: 12px;
  }

  .summary-card {
    background:
      linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(255, 250, 244, 0.95)),
      linear-gradient(135deg, rgba(196, 107, 35, 0.05), transparent 55%);
    border: 1px solid rgba(196, 107, 35, 0.08);
    border-radius: 18px;
    box-shadow: 0 14px 28px rgba(24, 74, 69, 0.05);
  }

  .summary-label {
    color: #7d6c57;
    font-size: 13px;
    margin-bottom: 8px;
  }

  .summary-value {
    color: var(--report-deep);
    font-size: 28px;
    font-weight: 600;
    line-height: 1.1;
  }

  .summary-foot {
    color: #9b8f81;
    font-size: 12px;
    margin-top: 10px;
  }

  .table-card {
    background: rgba(255, 253, 250, 0.98);
    border: 1px solid rgba(196, 107, 35, 0.08);
    border-radius: 20px;
    box-shadow: 0 18px 40px rgba(24, 74, 69, 0.06);
  }

  .card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }

  .card-title {
    color: var(--report-deep);
    font-size: 18px;
    font-weight: 600;
  }

  .card-subtitle {
    color: #7d6c57;
    font-size: 13px;
    margin-top: 4px;
  }

  .card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 12px;
  }

  .card-tag-item {
    background: rgba(196, 107, 35, 0.08);
    border: 1px solid rgba(196, 107, 35, 0.1);
    border-radius: 999px;
    color: #865b34;
    font-size: 12px;
    line-height: 1;
    padding: 8px 12px;
  }

  .main-cell {
    color: var(--report-deep);
    font-weight: 500;
  }

  .sub-cell {
    color: #a28f7d;
    font-size: 12px;
    line-height: 1.4;
  }

  :deep(.report-table .el-table__cell) {
    padding: 10px 0;
  }

  :deep(.report-table) {
    border-radius: 14px;
    overflow: hidden;
  }

  :deep(.report-table .el-table__header-wrapper th) {
    background: linear-gradient(180deg, #f4eadb 0%, #efe0ca 100%);
    color: #4c4d4f;
    font-weight: 600;
  }

  :deep(.report-table .el-table__row:nth-child(even) td) {
    background: rgba(250, 244, 235, 0.55);
  }

  .empty-panel {
    align-items: center;
    background: linear-gradient(180deg, rgba(247, 239, 227, 0.72), rgba(255, 252, 246, 0.96));
    border: 1px dashed rgba(196, 107, 35, 0.22);
    border-radius: 18px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    margin-top: 16px;
    padding: 36px 20px;
    text-align: center;
  }

  .empty-icon {
    align-items: center;
    background: linear-gradient(135deg, #c46b23, #d08d4e);
    border-radius: 18px;
    color: #fff8ef;
    display: inline-flex;
    font-size: 24px;
    font-weight: 700;
    height: 58px;
    justify-content: center;
    letter-spacing: 0.08em;
    width: 58px;
  }

  .empty-title {
    color: var(--report-deep);
    font-size: 18px;
    font-weight: 600;
    margin-top: 16px;
  }

  .empty-desc {
    color: #7d6c57;
    font-size: 13px;
    line-height: 1.8;
    margin-top: 8px;
    max-width: 520px;
  }
}

@media (max-width: 1200px) {
  .report-page {
    .hero-grid {
      grid-template-columns: repeat(1, minmax(0, 1fr));
    }

    .summary-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }
}

@media (max-width: 768px) {
  .report-page {
    .summary-grid {
      grid-template-columns: repeat(1, minmax(0, 1fr));
    }

    .card-header {
      align-items: flex-start;
      flex-direction: column;
    }
  }
}
</style>
