<template>
  <div class="report" v-if="project">
    <div class="rpt-bar no-print">
      <a @click="router.back()">← 返回</a>
      <span class="rpt-title">预测报告</span>
      <a-button type="primary" size="small" @click="printReport">打印 / 导出 PDF</a-button>
    </div>

    <div class="sheet">
      <!-- 封面 / 项目信息 -->
      <div class="cover">
        <div class="cover-tag">室内装修工程污染物预测报告</div>
        <h1>{{ project.name }}</h1>
        <div class="cover-meta">
          <span>项目ID：{{ project.id }}</span>
          <span>项目类型：{{ project.type }}</span>
          <span>所在城市：{{ project.province }}/{{ project.city }}</span>
          <span>建筑面积：{{ project.area }}m²</span>
        </div>
        <div class="cover-rating">
          预测评级 <b :class="'r-' + (project.rating || 'A')">{{ project.rating || '-' }}</b>
          <span class="gen">生成时间：{{ fmt(project.reportGeneratedAt) }}</span>
        </div>
        <div class="cover-summary">
          预测结果：共 {{ project.spaces.length }} 个空间，其中
          <b :class="{ bad: overSpaces > 0 }">{{ overSpaces }}</b> 个存在污染物浓度超标。
          依据 {{ standardsUsed }}。
        </div>
      </div>

      <!-- 各空间 -->
      <div class="space-block" v-for="(s, idx) in project.spaces" :key="s.id">
        <div class="sb-head">
          <h2>空间 {{ idx + 1 }} · {{ s.name }}</h2>
          <span class="sb-meta">{{ s.type }} · {{ s.area }}m² · {{ s.temperature }}℃ · {{ s.humidity }}%rh · 通风 {{ s.ventilationRate }}次/h · {{ s.standard }}</span>
        </div>

        <table class="conc-table">
          <thead><tr><th>污染物</th><th v-for="p in pollutants" :key="p">{{ labels[p].zh }}</th></tr></thead>
          <tbody>
            <tr><td>限值 (mg/m³)</td><td v-for="p in pollutants" :key="p">{{ limitOf(s, p) }}</td></tr>
            <tr>
              <td>预测浓度 (mg/m³)</td>
              <td v-for="p in pollutants" :key="p" :class="{ over: isOver(s, p) }">
                {{ fmt3(s.predictedConc?.[p]) }}
              </td>
            </tr>
            <tr><td>判定</td><td v-for="p in pollutants" :key="p" :class="{ over: isOver(s, p) }">{{ isOver(s, p) ? '超标' : '达标' }}</td></tr>
          </tbody>
        </table>

        <!-- 污染源溯源（仅超标污染物） -->
        <div v-if="overPollutants(s).length" class="trace">
          <div class="trace-h">污染源溯源</div>
          <div v-for="p in overPollutants(s)" :key="p" class="trace-pol">
            <div class="tp-name">{{ labels[p].zh }}（超标）主要污染源:<b>{{ sourceNames(s, p) }}</b></div>
            <div class="bars">
              <div class="bar" v-for="(c, i) in ranked(s, p)" :key="c.id">
                <span class="bn">{{ c.name }}<em v-if="isSource(s, p, c.id)">（污染源）</em></span>
                <span class="bt"><span class="bf" :style="{ width: Math.max(2, c.rate / ranked(s,p)[0].rate * 100) + '%', background: i === 0 ? '#bf4a30' : i === 1 ? '#ca8326' : '#1f7a5a' }" /></span>
                <span class="bv">{{ (c.rate * 100).toFixed(1) }}%</span>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="foot">依据 GB/T 18883-2022 · GB 50325-2020 · 预测结果仅供参考，以 CMA 检测为准</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { POLLUTANTS, POLLUTANT_LABELS, STANDARD_LIMITS, type Pollutant, type StandardCode } from '@airpredict/shared';
import { getProject, type ProjectDetail, type SpaceRow } from '../api/projects';

const route = useRoute();
const router = useRouter();
const project = ref<ProjectDetail | null>(null);
const pollutants = POLLUTANTS;
const labels = POLLUTANT_LABELS;

const fmt = (s?: string) => (s ? new Date(s).toLocaleString() : '-');
const fmt3 = (n?: number) => (n == null ? '-' : Number(n).toFixed(3));
const limitsOf = (s: SpaceRow) => STANDARD_LIMITS[(s.standard as StandardCode) || 'GB50325-2020'];
const limitOf = (s: SpaceRow, p: Pollutant) => limitsOf(s)[p];
const isOver = (s: SpaceRow, p: Pollutant) => (s.predictedConc?.[p] ?? 0) > limitOf(s, p);
const overPollutants = (s: SpaceRow) => POLLUTANTS.filter((p) => isOver(s, p));
const overSpaces = computed(() => (project.value?.spaces || []).filter((s) => overPollutants(s).length).length);
const standardsUsed = computed(() => [...new Set((project.value?.spaces || []).map((s) => s.standard))].join('、'));

interface Row { id: string; name: string; rate: number }
function ranked(s: SpaceRow, p: Pollutant): Row[] {
  return s.materials
    .map((m) => ({ id: m.materialId, name: m.material?.name || m.materialId, rate: m.contributionRate?.[p] ?? 0 }))
    .filter((r) => r.rate > 0)
    .sort((a, b) => b.rate - a.rate);
}
function sources(s: SpaceRow, p: Pollutant): Row[] {
  const out: Row[] = []; let cum = 0;
  for (const x of ranked(s, p)) { out.push(x); cum += x.rate; if (cum > 0.5) break; }
  return out;
}
const isSource = (s: SpaceRow, p: Pollutant, id: string) => sources(s, p).some((x) => x.id === id);
const sourceNames = (s: SpaceRow, p: Pollutant) => sources(s, p).map((x) => x.name).join('、');

function printReport() { window.print(); }

onMounted(async () => {
  project.value = await getProject(route.params.id as string);
});
</script>

<style scoped>
.report { background: #eef0f2; min-height: 100vh; padding-bottom: 40px; }
.rpt-bar { display: flex; align-items: center; gap: 16px; padding: 12px 24px; background: #fff; border-bottom: 1px solid #eee; position: sticky; top: 0; z-index: 5; }
.rpt-bar a { color: #b4232a; cursor: pointer; }
.rpt-title { flex: 1; font-weight: 600; }
.sheet { max-width: 900px; margin: 20px auto; background: #fff; padding: 40px 48px; box-shadow: 0 2px 12px rgba(0,0,0,.08); }
.cover { border-bottom: 2px solid #b4232a; padding-bottom: 20px; margin-bottom: 24px; }
.cover-tag { color: #b4232a; font-size: 13px; font-weight: 600; letter-spacing: 1px; }
.cover h1 { font-size: 28px; margin: 8px 0 16px; }
.cover-meta { display: flex; flex-wrap: wrap; gap: 6px 24px; color: #555; font-size: 14px; }
.cover-rating { margin-top: 16px; font-size: 15px; }
.cover-rating b { font-size: 22px; margin: 0 8px; }
.cover-rating b.r-A { color: #2f8f5b; } .cover-rating b.r-B { color: #2778c4; } .cover-rating b.r-C { color: #ca8326; } .cover-rating b.r-D { color: #bf4a30; }
.cover-rating .gen { color: #999; font-size: 13px; margin-left: 16px; }
.cover-summary { margin-top: 14px; color: #444; }
.cover-summary b { color: #2f8f5b; } .cover-summary b.bad { color: #bf4a30; }
.space-block { margin-bottom: 30px; page-break-inside: avoid; }
.sb-head h2 { font-size: 18px; margin: 0; }
.sb-meta { color: #888; font-size: 13px; }
.conc-table { width: 100%; border-collapse: collapse; margin: 12px 0; }
.conc-table th, .conc-table td { border: 1px solid #e8e8e8; padding: 8px 10px; text-align: center; font-size: 13px; }
.conc-table th { background: #fafafa; }
.conc-table td:first-child, .conc-table th:first-child { text-align: left; color: #666; }
.conc-table td.over { color: #bf4a30; font-weight: 700; }
.trace { background: #fcf8f6; border: 1px solid #f0e0d8; border-radius: 8px; padding: 14px 16px; }
.trace-h { font-weight: 600; color: #b4232a; margin-bottom: 10px; }
.trace-pol { margin-bottom: 14px; }
.tp-name { font-size: 13px; margin-bottom: 8px; }
.bars { display: flex; flex-direction: column; gap: 6px; }
.bar { display: grid; grid-template-columns: 200px 1fr 52px; align-items: center; gap: 10px; font-size: 12px; }
.bar em { color: #bf4a30; font-style: normal; font-weight: 700; }
.bt { height: 12px; background: #eee; border-radius: 4px; overflow: hidden; }
.bf { display: block; height: 100%; }
.bv { text-align: right; font-weight: 700; }
.foot { color: #aaa; font-size: 12px; text-align: center; margin-top: 30px; border-top: 1px solid #eee; padding-top: 16px; }
@media print {
  .no-print { display: none; }
  .report { background: #fff; }
  .sheet { box-shadow: none; margin: 0; max-width: none; }
}
</style>
