<template>
  <article class="alarm-evidence">
    <header class="evidence-hero">
      <div>
        <div class="evidence-tags">
          <el-tag :type="severityTag(alarm.severity)" effect="dark">{{ severityLabel(alarm.severity) }}</el-tag>
          <el-tag :type="statusTag(alarm.status)" effect="plain">{{ statusLabel(alarm.status) }}</el-tag>
          <el-tag v-if="alarm.suppressed" type="info" effect="plain">已抑制</el-tag>
        </div>
        <h2>{{ alarm.scene || "未命名告警" }}</h2>
        <p>{{ alarm.category || "未分类" }} · {{ alarm.alarm_id || "-" }}</p>
      </div>
      <div class="confidence-score">
        <span>模型置信度</span>
        <strong>{{ confidencePercent }}%</strong>
        <el-progress :percentage="confidencePercent" :show-text="false" :stroke-width="7" :color="confidenceColor" />
      </div>
    </header>

    <div class="evidence-summary-grid">
      <div>
        <span>识别模型</span>
        <strong>{{ aiResult.model_name || "-" }}</strong>
        <small>{{ aiResult.model_version || "版本未知" }}</small>
      </div>
      <div>
        <span>原始资源</span>
        <strong class="compact-id">{{ aiResult.resource_id || evidenceInfo.resource_id || "-" }}</strong>
        <small>{{ resourceTypeLabel(aiResult.resource_type) }}</small>
      </div>
      <div>
        <span>线路位置</span>
        <strong>{{ location.mileage || "里程待补充" }}</strong>
        <small>{{ location.line_id || "线路待补充" }}</small>
      </div>
      <div>
        <span>距线路</span>
        <strong>{{ distanceText }}</strong>
        <small>{{ geometryTypeLabel(geometry.type) }}</small>
      </div>
    </div>

    <section class="evidence-section">
      <div class="section-heading">
        <div><strong>证据形成过程</strong><span>从原始资源到告警生成的可追溯链路</span></div>
      </div>
      <el-steps direction="vertical" :active="4" finish-status="success" class="evidence-steps">
        <el-step title="原始资源" :description="String(aiResult.resource_id || evidenceInfo.resource_id || '-')" />
        <el-step title="模型识别" :description="`${aiResult.model_name || '-'} / ${aiResult.model_version || '-'}`" />
        <el-step title="规则判定" :description="ruleSummary" />
        <el-step title="告警生成" :description="`${statusLabel(alarm.status)} / ${locationSummary}`" />
      </el-steps>
    </section>

    <section class="evidence-section">
      <div class="section-heading">
        <div><strong>规则判定依据</strong><span>触发告警等级与处置流程的业务条件</span></div>
      </div>
      <div v-if="ruleHits.length" class="rule-hit-list">
        <span v-for="(rule, index) in ruleHits" :key="`${rule}-${index}`"><i>{{ index + 1 }}</i>{{ rule }}</span>
      </div>
      <el-empty v-else description="暂无规则命中信息" :image-size="46" />
      <div v-if="alarm.suppression_reason" class="suppression-note">
        <strong>抑制原因</strong><span>{{ alarm.suppression_reason }}</span>
      </div>
    </section>

    <section class="evidence-section">
      <div class="section-heading">
        <div><strong>空间定位</strong><span>业务坐标与检测区域摘要</span></div>
      </div>
      <div class="location-panel">
        <div class="location-mark" aria-hidden="true"><i></i><span></span></div>
        <dl>
          <div><dt>线路</dt><dd>{{ location.line_id || "-" }}</dd></div>
          <div><dt>里程</dt><dd>{{ location.mileage || "-" }}</dd></div>
          <div><dt>距线路</dt><dd>{{ distanceText }}</dd></div>
          <div><dt>几何类型</dt><dd>{{ geometryTypeLabel(geometry.type) }}</dd></div>
          <div class="coordinate-row"><dt>坐标/区域</dt><dd>{{ coordinateSummary }}</dd></div>
        </dl>
      </div>
    </section>

    <section v-if="measurementItems.length" class="evidence-section">
      <div class="section-heading">
        <div><strong>关键量测</strong><span>模型输出与规则计算使用的结构化指标</span></div>
      </div>
      <div class="measurement-grid">
        <div v-for="item in measurementItems" :key="item.key">
          <span>{{ item.label }}</span>
          <strong>{{ item.value }}</strong>
          <small v-if="item.note">{{ item.note }}</small>
        </div>
      </div>
    </section>

    <section v-if="attributeItems.length" class="evidence-section">
      <div class="section-heading">
        <div><strong>模型运行信息</strong><span>用于结果复现和运行环境追溯</span></div>
      </div>
      <dl class="runtime-list">
        <div v-for="item in attributeItems" :key="item.key"><dt>{{ item.label }}</dt><dd>{{ item.value }}</dd></div>
      </dl>
    </section>

    <slot name="actions" />

    <el-collapse class="technical-data">
      <el-collapse-item title="原始技术数据（仅用于排障与审计）" name="raw">
        <pre class="detail-json">{{ rawTechnicalData }}</pre>
      </el-collapse-item>
    </el-collapse>
  </article>
</template>

<script setup lang="ts">
import { computed } from "vue";
import { safeObject, severityLabel, statusLabel, statusTag, type Row } from "../../types/demo-run";

const props = defineProps<{ evidence: Row }>();

const alarm = computed(() => safeObject(props.evidence.alarm));
const aiResult = computed(() => safeObject(props.evidence.ai_result));
const evidenceInfo = computed(() => safeObject(alarm.value.evidence));
const location = computed(() => safeObject(alarm.value.location));
const geometry = computed(() => {
  const locationGeometry = safeObject(location.value.geometry);
  return Object.keys(locationGeometry).length ? locationGeometry : safeObject(aiResult.value.geometry);
});
const measurements = computed(() => safeObject(aiResult.value.measurements));
const attributes = computed(() => safeObject(aiResult.value.attributes));
const ruleHits = computed(() => Array.isArray(alarm.value.rule_hits) ? alarm.value.rule_hits.map(String) : []);
const confidencePercent = computed(() => Math.max(0, Math.min(100, Math.round(Number(alarm.value.confidence || 0) * 100))));
const confidenceColor = computed(() => confidencePercent.value >= 85 ? "#15803d" : confidencePercent.value >= 70 ? "#d97706" : "#dc2626");
const distanceText = computed(() => {
  const value = location.value.distance_to_track_m ?? measurements.value.distance_to_track_m;
  return value === "" || value === null || value === undefined ? "待测量" : `${formatNumber(value)} m`;
});
const locationSummary = computed(() => [location.value.line_id, location.value.mileage, distanceText.value].filter(Boolean).join(" / ") || "位置待补充");
const ruleSummary = computed(() => ruleHits.value.join(" / ") || "未记录规则命中");
const coordinateSummary = computed(() => formatGeometry(geometry.value));
const measurementItems = computed(() => Object.entries(measurements.value).map(([key, value]) => ({
  key,
  label: fieldMeta[key]?.label || humanizeKey(key),
  value: formatMeasurement(key, value),
  note: fieldMeta[key]?.note || ""
})));
const attributeItems = computed(() => Object.entries(attributes.value).map(([key, value]) => ({
  key,
  label: attributeLabels[key] || humanizeKey(key),
  value: formatValue(value)
})));
const rawTechnicalData = computed(() => JSON.stringify({
  location: location.value,
  geometry: geometry.value,
  measurements: measurements.value,
  attributes: attributes.value,
  evidence: evidenceInfo.value
}, null, 2));

const fieldMeta: Record<string, { label: string; unit?: string; note?: string; percent?: boolean }> = {
  distance_to_track_m: { label: "距线路", unit: "m", note: "空间规则输入" },
  distance_to_contact_network_m: { label: "距接触网", unit: "m" },
  temperature_c: { label: "目标温度", unit: "℃", note: "热成像测温" },
  relative_rise_c: { label: "相对温升", unit: "℃" },
  volume_change_m3: { label: "体积变化", unit: "m³" },
  change_area_m2: { label: "变化面积", unit: "m²" },
  width_cm: { label: "目标宽度", unit: "cm" },
  length_cm: { label: "目标长度", unit: "cm" },
  tree_height_m: { label: "树木高度", unit: "m" },
  max_height_diff_m: { label: "最大高差", unit: "m" },
  registration_error_m: { label: "配准误差", unit: "m" },
  registration_precision_m: { label: "配准精度", unit: "m" },
  max_deformation_m: { label: "最大形变", unit: "m" },
  area_ratio: { label: "区域占比", percent: true },
  change_score: { label: "变化得分", percent: true },
  in_protected_area: { label: "位于防护区", note: "空间规则输入" },
  maintenance_window: { label: "处于天窗期", note: "作业时间规则" },
  quality_passed: { label: "质量校验" },
  point_count: { label: "有效点数" },
  mileage: { label: "检测里程" }
};

const attributeLabels: Record<string, string> = {
  execution_mode: "推理模式",
  adapter: "推理适配器",
  deployment_id: "运行部署",
  analysis: "分析类型",
  parser: "解析器",
  fallback_reason: "降级原因",
  configured_model: "配置模型",
  test_mode: "测试模式",
  coordinate_space: "坐标空间",
  model_group: "模型组",
  pixel_area: "像素面积"
};

function severityTag(value: unknown): "danger" | "warning" | "info" | "success" {
  return ({ critical: "danger", high: "warning", medium: "info", low: "success" } as Record<string, "danger" | "warning" | "info" | "success">)[String(value)] || "info";
}

function resourceTypeLabel(value: unknown) {
  return ({ image: "可见光图像", video: "巡检视频", thermal: "红外热成像", tif: "栅格影像", pointcloud: "点云数据" } as Record<string, string>)[String(value)] || String(value || "资源类型未知");
}

function geometryTypeLabel(value: unknown) {
  return ({ Point: "地理坐标点", BBox: "目标检测框", Polygon: "目标区域", LineString: "线路范围" } as Record<string, string>)[String(value)] || String(value || "无几何信息");
}

function formatGeometry(value: Row) {
  const type = String(value.type || "");
  const coordinates = value.coordinates;
  if (!Array.isArray(coordinates) || coordinates.length === 0) return "暂无坐标";
  if (type === "Point") return coordinates.slice(0, 2).map((item) => formatNumber(item, 6)).join(", ");
  if (type === "BBox" && coordinates.length >= 4) {
    return `${coordinates.slice(0, 2).map((item) => formatNumber(item, 3)).join(", ")} → ${coordinates.slice(2, 4).map((item) => formatNumber(item, 3)).join(", ")}`;
  }
  if (type === "Polygon") {
    const points = Array.isArray(coordinates[0]) ? coordinates[0] : coordinates;
    return `${points.length} 个边界点${value.coordinate_space ? ` · ${value.coordinate_space}` : ""}`;
  }
  return `${coordinates.length} 组坐标`;
}

function formatMeasurement(key: string, value: unknown) {
  const meta = fieldMeta[key];
  if (meta?.percent) return `${formatNumber(Number(value) * 100)}%`;
  const formatted = formatValue(value);
  return meta?.unit && typeof value === "number" ? `${formatted} ${meta.unit}` : formatted;
}

function formatValue(value: unknown): string {
  if (typeof value === "boolean") return value ? "是" : "否";
  if (typeof value === "number") return formatNumber(value);
  if (Array.isArray(value)) return value.map(formatValue).join("、") || "-";
  if (value && typeof value === "object") {
    const entries = Object.entries(value as Record<string, unknown>);
    return entries.length ? entries.map(([key, item]) => `${humanizeKey(key)}：${formatValue(item)}`).join("；") : "-";
  }
  return String(value ?? "-");
}

function formatNumber(value: unknown, digits = 2) {
  const number = Number(value);
  if (!Number.isFinite(number)) return String(value ?? "-");
  return number.toLocaleString("zh-CN", { maximumFractionDigits: digits });
}

function humanizeKey(key: string) {
  return key.replaceAll("_", " ");
}
</script>

<style scoped>
.alarm-evidence { color: #1e293b; }
.evidence-hero { padding: 2px 0 18px; display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; border-bottom: 1px solid #e2e8f0; }
.evidence-tags { display: flex; gap: 7px; flex-wrap: wrap; }
.evidence-hero h2 { margin: 11px 0 5px; color: #17365d; font-size: 22px; }
.evidence-hero p { margin: 0; color: #64748b; font-size: 12px; }
.confidence-score { width: 150px; flex: 0 0 auto; }
.confidence-score span { display: block; color: #64748b; font-size: 11px; }
.confidence-score strong { display: block; margin: 4px 0 8px; color: #17365d; font-size: 26px; line-height: 1; }
.evidence-summary-grid { margin: 16px 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
.evidence-summary-grid > div { min-width: 0; padding: 12px; border: 1px solid #dce4ed; border-radius: 6px; background: #f8fafc; }
.evidence-summary-grid span, .evidence-summary-grid small { display: block; color: #64748b; font-size: 11px; }
.evidence-summary-grid strong { display: block; margin: 6px 0 3px; color: #17365d; font-size: 15px; }
.compact-id { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: Consolas, monospace; font-size: 12px !important; }
.evidence-section { margin-top: 16px; padding: 15px; border: 1px solid #dce4ed; border-radius: 7px; background: #fff; }
.section-heading { margin-bottom: 13px; display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; }
.section-heading strong, .section-heading span { display: block; }
.section-heading strong { color: #17365d; font-size: 15px; }
.section-heading span { margin-top: 4px; color: #94a3b8; font-size: 11px; }
.evidence-steps { padding: 2px 4px 0; }
.rule-hit-list { display: grid; gap: 8px; }
.rule-hit-list span { min-height: 38px; padding: 8px 10px; display: flex; align-items: center; gap: 9px; border-radius: 5px; background: #fff7ed; color: #9a3412; font-size: 13px; font-weight: 700; }
.rule-hit-list i { width: 21px; height: 21px; display: inline-grid; place-items: center; flex: 0 0 auto; border-radius: 50%; background: #fed7aa; color: #9a3412; font-size: 11px; font-style: normal; }
.suppression-note { margin-top: 10px; padding: 10px; display: grid; gap: 4px; border-radius: 5px; background: #f1f5f9; }
.suppression-note strong { color: #475569; font-size: 12px; }
.suppression-note span { color: #64748b; font-size: 12px; }
.location-panel { display: grid; grid-template-columns: 100px minmax(0, 1fr); gap: 14px; align-items: stretch; }
.location-mark { min-height: 122px; position: relative; display: grid; place-items: center; overflow: hidden; border-radius: 6px; background: linear-gradient(135deg, #e0f2fe, #eff6ff); }
.location-mark::before, .location-mark::after { content: ""; position: absolute; width: 150%; height: 1px; background: rgba(30, 64, 175, .13); transform: rotate(-24deg); }
.location-mark::after { transform: rotate(32deg); }
.location-mark i { width: 28px; height: 28px; position: relative; z-index: 1; border: 7px solid #dc2626; border-radius: 50% 50% 50% 0; background: #fff; transform: rotate(-45deg); box-shadow: 0 4px 12px rgba(220, 38, 38, .22); }
.location-mark span { width: 38px; height: 8px; position: absolute; bottom: 28px; border-radius: 50%; background: rgba(15, 23, 42, .14); filter: blur(1px); }
.location-panel dl, .runtime-list { margin: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px; }
.location-panel dl > div, .runtime-list > div { min-width: 0; }
.location-panel dt, .runtime-list dt { color: #94a3b8; font-size: 10px; }
.location-panel dd, .runtime-list dd { margin: 4px 0 0; color: #334155; font-size: 12px; font-weight: 700; word-break: break-word; }
.coordinate-row { grid-column: 1 / -1; }
.measurement-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.measurement-grid > div { min-width: 0; padding: 10px; border-radius: 5px; background: #f8fafc; }
.measurement-grid span, .measurement-grid small { display: block; color: #64748b; font-size: 10px; }
.measurement-grid strong { display: block; margin: 5px 0 3px; color: #0f766e; font-size: 17px; word-break: break-word; }
.technical-data { margin-top: 16px; }
.technical-data :deep(.el-collapse-item__header) { color: #64748b; font-size: 12px; }
.technical-data .detail-json { margin: 0; max-height: 300px; }
@media (max-width: 640px) {
  .evidence-hero { display: grid; }
  .confidence-score { width: 100%; }
  .evidence-summary-grid, .measurement-grid { grid-template-columns: 1fr; }
  .location-panel { grid-template-columns: 1fr; }
  .location-mark { min-height: 90px; }
}
</style>
