<template>
  <div class="sales-page">
    <section class="header-bar">
      <h1 class="header-title">性能评估</h1>
      <div class="header-actions">
        <el-button size="small" type="success" :loading="loading" icon="el-icon-refresh" @click="startEvaluation">重新评估</el-button>
        <el-button size="small" type="primary" icon="el-icon-download" @click="exportReport">导出报告</el-button>
      </div>
    </section>

    <section class="filter-bar">
      <div class="filter-item">
        <label>时间范围</label>
        <el-select v-model="timeRange" size="small">
          <el-option label="近 7 天" value="7" />
          <el-option label="近 15 天" value="15" />
          <el-option label="近 30 天" value="30" />
          <el-option label="近 90 天" value="90" />
        </el-select>
      </div>
      <div class="filter-item">
        <label>产品范围</label>
        <el-select v-model="productRange" size="small">
          <el-option label="全部产品" value="all" />
          <el-option label="主力产品" value="main" />
          <el-option label="新品" value="new" />
          <el-option label="淘汰品" value="old" />
        </el-select>
      </div>
      <div class="filter-item">
        <label>预测模型</label>
        <el-select v-model="model" size="small">
          <el-option label="当前模型" value="current" />
          <el-option label="历史模型 v1" value="v1" />
          <el-option label="历史模型 v2" value="v2" />
        </el-select>
      </div>
    </section>

    <section class="metrics-panel">
      <div class="metric-card"><span>MAPE</span><strong>{{ mape }}<em>%</em></strong><b>良好</b></div>
      <div class="metric-card rmse"><span>RMSE</span><strong>{{ formatNumber(rmse) }}</strong><em>件</em></div>
      <div class="metric-card mae"><span>MAE</span><strong>{{ formatNumber(mae) }}</strong><em>件</em></div>
      <div class="metric-card r2"><span>R²</span><strong>{{ r2 }}</strong><b>拟合度良好</b></div>
      <div class="gauge-card">
        <div class="gauge" :style="{ background: gaugeGradient }"><div><strong>{{ accuracy }}%</strong><span>整体准确度</span></div></div>
        <div class="gauge-summary">
          <div><span>评估样本数</span><strong>{{ formatNumber(evaluationRows.length) }}</strong></div>
          <div><span>达标率</span><strong>{{ passRate }}%</strong></div>
          <div><span>异常点数</span><strong>{{ abnormalCount }}</strong></div>
          <div><span>平均误差</span><strong>{{ mape }}%</strong></div>
        </div>
      </div>
    </section>

    <section class="panel">
      <div class="panel-head">
        <h3>预测值 vs 实际值对比</h3>
        <div class="legend"><span><i class="blue"></i>实际值</span><span><i class="orange"></i>预测值</span><span><i class="gray"></i>误差区域</span></div>
      </div>
      <div ref="comparisonChart" class="chart"></div>
      <div v-if="!hasEvaluation" class="empty-hint">暂无回测数据，请先在趋势预测页上传并完成一次分析。</div>
    </section>

    <section class="panel">
      <div class="panel-head">
        <h3>误差分析明细</h3>
        <el-input v-model="dateKeyword" size="small" prefix-icon="el-icon-search" placeholder="搜索日期" />
      </div>
      <el-table :data="filteredRows" size="small" :row-class-name="rowClassName">
        <el-table-column prop="date" label="日期" min-width="120" />
        <el-table-column prop="actual" label="实际值" min-width="100" />
        <el-table-column prop="predicted" label="预测值" min-width="100" />
        <el-table-column prop="absError" label="绝对误差" min-width="100" />
        <el-table-column prop="relativeError" label="相对误差" min-width="100">
          <template slot-scope="{ row }"><span :class="errorClass(row.relativeError)">{{ row.relativeError }}%</span></template>
        </el-table-column>
        <el-table-column prop="status" label="是否异常" min-width="120" />
      </el-table>
    </section>

    <section class="panel">
      <h3>优化建议</h3>
      <div class="suggestions">
        <div v-for="item in suggestions" :key="item.issue" class="suggestion-card" :class="item.level">
          <strong>{{ item.issue }}</strong>
          <p>{{ item.reason }}</p>
          <em>{{ item.solution }}</em>
          <el-button size="mini" type="text" @click="copySuggestion(item)">复制</el-button>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import { backtestSalesTrend } from '@/api/client'

export default {
  name: 'SalePerformanceEvaluation',
  data() {
    return {
      chart: null,
      loading: false,
      timeRange: '30',
      productRange: 'all',
      model: 'current',
      dateKeyword: '',
      backtest: {}
    }
  },
  computed: {
    historicalSeries() {
      return this.evaluationRows.map(row => row.actual)
    },
    historicalDates() {
      return this.evaluationRows.map(row => row.date)
    },
    predictedSeries() {
      return this.evaluationRows.map(row => row.predicted)
    },
    hasEvaluation() {
      return this.evaluationRows.length > 0
    },
    evaluationRows() {
      return (this.backtest.rows || []).map(row => ({
        ...row,
        actual: Math.round(Number(row.actual || 0)),
        predicted: Math.round(Number(row.predicted || 0)),
        absError: Math.round(Number(row.absError || 0)),
        relativeError: Number(row.relativeError || 0)
      }))
    },
    filteredRows() {
      if (!this.dateKeyword) return this.evaluationRows
      return this.evaluationRows.filter(row => row.date.includes(this.dateKeyword))
    },
    mape() {
      return Number(((this.backtest.metrics || {}).mape) || 0).toFixed(1)
    },
    mae() {
      return Number(((this.backtest.metrics || {}).mae) || 0)
    },
    rmse() {
      return Number(((this.backtest.metrics || {}).rmse) || 0)
    },
    r2() {
      return Number(((this.backtest.metrics || {}).r2) || 0).toFixed(2)
    },
    accuracy() {
      return Math.max(0, 100 - Number(this.mape)).toFixed(1)
    },
    passRate() {
      const passed = this.evaluationRows.filter(row => row.relativeError <= 15).length
      return ((passed / Math.max(1, this.evaluationRows.length)) * 100).toFixed(1)
    },
    abnormalCount() {
      return this.evaluationRows.filter(row => row.status === '异常').length
    },
    gaugeGradient() {
      const degree = Number(this.accuracy) * 3.6
      return `conic-gradient(#667eea 0deg,#764ba2 ${degree}deg,#e5e7eb ${degree}deg)`
    },
    suggestions() {
      return [
        { level: 'warning', issue: `当前异常点 ${this.abnormalCount} 个`, reason: '高误差日期可能存在促销或流量突变。', solution: '建议补充活动日历、平台流量和节假日特征。' },
        { level: 'info', issue: `整体 MAPE 为 ${this.mape}%`, reason: '模型整体表现稳定，但仍需关注异常样本。', solution: '建议定期回测并按品类拆分评估。' },
        { level: 'primary', issue: 'RMSE 接近波动阈值', reason: '连续多日误差偏高会影响库存和营销决策。', solution: '建议重新训练模型并调整季节性参数。' }
      ]
    }
  },
  watch: {
    timeRange() {
      this.startEvaluation()
    }
  },
  mounted() {
    this.chart = echarts.init(this.$refs.comparisonChart)
    window.addEventListener('resize', this.resize)
    this.startEvaluation()
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resize)
    if (this.chart) this.chart.dispose()
  },
  methods: {
    async startEvaluation() {
      this.loading = true
      try {
        const response = await backtestSalesTrend({ window: Number(this.timeRange) })
        if (response && response.success) {
          this.backtest = response.data || {}
        } else {
          throw new Error((response && response.message) || '回测失败')
        }
      } catch (error) {
        this.backtest = {}
        this.$modal.msgError(error.message || '请先上传并分析销售数据后再评估')
      } finally {
        this.loading = false
        this.$nextTick(this.renderChart)
      }
    },
    renderChart() {
      if (!this.chart) return
      const rows = this.evaluationRows
      this.chart.setOption({
        tooltip: { trigger: 'axis' },
        grid: { left: 45, right: 24, bottom: 40, top: 25 },
        xAxis: { type: 'category', data: rows.map(row => row.date) },
        yAxis: { type: 'value' },
        series: [
          { name: '实际值', type: 'scatter', symbolSize: 9, data: rows.map(row => row.actual), itemStyle: { color: '#3b82f6' } },
          { name: '预测值', type: 'line', smooth: true, lineStyle: { type: 'dashed' }, data: rows.map(row => row.predicted), itemStyle: { color: '#f59e0b' } }
        ]
      })
    },
    rowClassName({ row }) {
      return row.status === '异常' ? 'abnormal-row' : ''
    },
    errorClass(value) {
      if (value <= 5) return 'low'
      if (value <= 15) return 'medium'
      return 'high'
    },
    copySuggestion(item) {
      const text = `${item.issue}\n${item.reason}\n${item.solution}`
      navigator.clipboard && navigator.clipboard.writeText(text)
      this.$modal.msgSuccess('已复制')
    },
    exportReport() {
      if (!this.hasEvaluation) {
        this.$modal.msgWarning('暂无可导出的评估结果')
        return
      }
      const blob = new Blob([JSON.stringify({ metrics: { mape: this.mape, rmse: this.rmse, mae: this.mae, r2: this.r2 }, rows: this.evaluationRows }, null, 2)], { type: 'application/json;charset=utf-8' })
      const url = URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = url
      link.download = `sale_evaluation_${Date.now()}.json`
      link.click()
      URL.revokeObjectURL(url)
    },
    formatNumber(value) {
      return Math.round(Number(value || 0)).toLocaleString()
    },
    resize() {
      if (this.chart) this.chart.resize()
    }
  }
}
</script>

<style scoped lang="scss">
.sales-page { padding: 20px; max-width: 1400px; margin: 0 auto; background: #f0f2f5; min-height: calc(100vh - 84px); }
.header-bar, .filter-bar, .panel, .metric-card, .gauge-card { background: #fff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,.06); }
.header-bar { display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; margin-bottom: 20px; gap: 16px; flex-wrap: wrap; }
.header-title { margin: 0; font-size: 20px; font-weight: 600; }
.header-actions { display: flex; gap: 10px; }
.filter-bar { display: flex; gap: 15px; align-items: flex-end; padding: 20px 24px; margin-bottom: 20px; flex-wrap: wrap; }
.filter-item { display: flex; flex-direction: column; gap: 6px; min-width: 150px; }
.filter-item label { color: #606266; font-size: 12px; }
.metrics-panel { display: grid; grid-template-columns: repeat(4,1fr); gap: 15px; margin-bottom: 20px; }
.metric-card { padding: 24px; text-align: center; position: relative; overflow: hidden; }
.metric-card::before { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 4px; background: linear-gradient(90deg,#667eea,#764ba2); }
.metric-card.rmse::before { background: linear-gradient(90deg,#f59e0b,#f97316); }
.metric-card.mae::before { background: linear-gradient(90deg,#3b82f6,#06b6d4); }
.metric-card.r2::before { background: linear-gradient(90deg,#10b981,#34d399); }
.metric-card span { color: #909399; }
.metric-card strong { display: block; font-size: 34px; margin: 8px 0; }
.metric-card em { color: #909399; font-style: normal; }
.metric-card b { background: #d4edda; color: #155724; border-radius: 16px; padding: 4px 12px; font-size: 12px; font-weight: 400; }
.gauge-card { grid-column: span 4; padding: 24px; display: flex; justify-content: center; align-items: center; gap: 60px; flex-wrap: wrap; }
.gauge { width: 180px; height: 180px; border-radius: 50%; position: relative; }
.gauge div { position: absolute; inset: 20px; border-radius: 50%; background: white; display: flex; align-items: center; justify-content: center; flex-direction: column; }
.gauge strong { font-size: 36px; color: #667eea; }
.gauge span { color: #909399; }
.gauge-summary { display: flex; gap: 36px; flex-wrap: wrap; }
.gauge-summary span { display: block; color: #909399; font-size: 12px; margin-bottom: 5px; }
.gauge-summary strong { font-size: 18px; }
.panel { padding: 24px; margin-bottom: 20px; }
.panel-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 16px; }
.panel-head h3, .panel h3 { margin: 0; font-size: 16px; }
.legend { display: flex; gap: 16px; color: #606266; font-size: 12px; flex-wrap: wrap; }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { width: 12px; height: 12px; border-radius: 50%; display: inline-block; }
.legend .blue { background: #3b82f6; }
.legend .orange { width: 20px; height: 2px; border-radius: 0; background: #f59e0b; }
.legend .gray { background: rgba(107,114,128,.2); border: 1px solid #9ca3af; }
.chart { height: 350px; }
.empty-hint { text-align: center; color: #909399; margin-top: -210px; height: 210px; pointer-events: none; }
.low { color: #67c23a; font-weight: 600; }
.medium { color: #e6a23c; font-weight: 600; }
.high { color: #f56c6c; font-weight: 600; }
::v-deep .abnormal-row { background: #fef2f2; }
.suggestions { display: flex; flex-direction: column; gap: 15px; }
.suggestion-card { border-left: 4px solid #667eea; background: #f8f9fa; border-radius: 8px; padding: 18px; }
.suggestion-card.warning { border-left-color: #f59e0b; }
.suggestion-card.info { border-left-color: #17a2b8; }
.suggestion-card p { color: #606266; margin: 8px 0; }
.suggestion-card em { color: #667eea; font-style: normal; }
@media (max-width: 1200px) { .metrics-panel { grid-template-columns: repeat(2,1fr); } .gauge-card { grid-column: span 2; } }
@media (max-width: 768px) { .metrics-panel { grid-template-columns: 1fr; } .gauge-card { grid-column: span 1; } }
</style>
