<template>
  <div class="app-container">
    <!-- 页面标题 -->
    <div class="page-header">
      <h2><i class="el-icon-data-analysis"></i> SPU生命周期详细分析</h2>
      <p class="page-desc">单个SPU的完整生命周期分析，包含趋势、指标和阶段详情</p>
    </div>

    <div class="upload-toolbar">
      <div class="toolbar-left">
        <el-upload
          ref="toolbarUpload"
          class="toolbar-upload"
          :limit="1"
          accept=".xlsx,.xls,.csv"
          :http-request="customUpload"
          :disabled="upload.isUploading"
          :on-change="handleFileChange"
          :before-upload="beforeUpload"
          :auto-upload="false"
          :show-file-list="false"
        >
          <el-button plain>上传文件</el-button>
        </el-upload>
        <el-button :loading="upload.isUploading" type="primary" @click="submitUpload">开始分析</el-button>
        <el-button type="success" :disabled="!hasResults" @click="exportResults">导出分析</el-button>
      </div>
      <div class="toolbar-status" v-if="upload.fileName">已上传：{{ upload.fileName }}</div>
      <div class="toolbar-status" v-else-if="upload.pendingFileName">已选择：{{ upload.pendingFileName }}</div>
      <div class="toolbar-status muted" v-else>未上传</div>
    </div>

    <!-- SPU选择 + 基础信息板块 -->
    <div class="bg-white rounded-xl p-6 mb-20 shadow-sm">
      <div class="flex flex-wrap items-center justify-between gap-4 mb-6">
        <div class="flex items-center gap-3">
          <label class="text-sm font-medium text-gray-700">选择SPU:</label>
          <select class="border border-gray-300 rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm spu-select"
                  v-model="selectedSpu">
            <option v-for="k in spuOptions" :key="k" :value="k">{{ k }}</option>
          </select>
        </div>

        <div class="flex items-center gap-2">
          <span class="text-sm font-medium text-gray-700">当前阶段:</span>
          <span class="px-3 py-1 bg-gradient-to-r from-yellow-100 to-amber-100 text-yellow-800 rounded-full text-sm font-medium flex items-center gap-2">
            {{ currentStage }}
          </span>
        </div>
      </div>

      <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
        <div class="p-4 border border-gray-200 rounded-lg bg-gray-50">
          <p class="text-xs text-gray-500 uppercase tracking-wide">SPU名称</p>
          <p class="text-lg font-medium text-gray-800 truncate">{{ selectedSpu }}</p>
        </div>
        <div class="p-4 border border-gray-200 rounded-lg bg-gray-50">
          <p class="text-xs text-gray-500 uppercase tracking-wide">生命周期完整性</p>
          <p class="text-lg font-medium" :class="detail && detail.is_complete ? 'text-green-700' : 'text-orange-600'">
            {{ detail && detail.is_complete ? '完整' : '不完整' }}
            <span v-if="detail && detail.completeness_score != null" class="ml-2 text-sm text-gray-500">
              (得分: {{ detail.completeness_score }}/100)
            </span>
          </p>
        </div>
        <div class="p-4 border border-gray-200 rounded-lg bg-gray-50">
          <p class="text-xs text-gray-500 uppercase tracking-wide">总销售额</p>
          <p class="text-lg font-medium text-gray-800">{{ formatCurrency(totalRevenue) }}</p>
        </div>
        <div class="p-4 border border-gray-200 rounded-lg bg-gray-50">
          <p class="text-xs text-gray-500 uppercase tracking-wide">总销量</p>
          <p class="text-lg font-medium text-gray-800">{{ totalQty }}</p>
        </div>
      </div>
    </div>

    <!-- 生命周期趋势图（含阶段分界可视化） -->
    <div class="bg-white rounded-xl p-6 mb-20 shadow-sm">
      <div class="flex justify-between items-center mb-6">
        <h3 class="text-lg font-semibold text-gray-800">SPU生命周期趋势图</h3>
        <div class="flex items-center gap-3">
          <div class="flex items-center gap-2">
            <span class="w-3 h-3 rounded-full bg-blue-500"></span>
            <span class="text-sm text-gray-600">销售额</span>
          </div>
          <div class="flex items-center gap-2">
            <span class="w-3 h-3 rounded-full bg-gray-500"></span>
            <span class="text-sm text-gray-600">销量</span>
          </div>
        </div>
      </div>
      <div class="h-96">
        <canvas ref="lifeCycleTrendRef"></canvas>
      </div>
      <div class="mt-4 space-y-2">
        <div v-if="detail && detail.is_complete" class="text-sm">
          <span :class="hasFourStages ? 'text-green-700 font-medium' : 'text-red-600 font-medium'">
            <i :class="hasFourStages ? 'fa fa-check-circle' : 'fa fa-exclamation-triangle'" class="mr-1"></i>
            {{ hasFourStages ? '阶段划分完整：已包含引入/成长/成熟/衰退四个阶段' : '阶段划分不完整：未包含所有四个标准阶段' }}
          </span>
        </div>
        <div v-if="detail && !detail.is_complete && detail.completeness_score != null" class="text-sm text-orange-600">
          <i class="fa fa-info-circle mr-1"></i>
          不完整生命周期SPU - 完整性评估得分：{{ detail.completeness_score }}/100 (需要聓80分以上才能被评为完整周期)
        </div>
      </div>
    </div>

    <!-- 基本指标与阶段分析分组 -->
    <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-20">
      <!-- 基本指标板块 -->
      <div class="bg-white rounded-xl p-6 shadow-sm space-y-6">
        <h3 class="text-lg font-semibold text-gray-800">基本指标</h3>
        <div>
          <div class="flex justify-between mb-2">
            <span class="text-sm text-gray-500">总销售额</span>
            <span class="text-sm font-medium text-gray-800">{{ formatCurrency(totalRevenue) }}</span>
          </div>
          <div class="progress-bar"><div class="progress-value bg-blue-500" :style="{ width: revenuePct+'%' }"></div></div>
        </div>
        <div>
          <div class="flex justify-between mb-2">
            <span class="text-sm text-gray-500">总销量</span>
            <span class="text-sm font-medium text-gray-800">{{ totalQty }}</span>
          </div>
          <div class="progress-bar"><div class="progress-value bg-gray-500" :style="{ width: qtyPct+'%' }"></div></div>
        </div>
        <div class="grid grid-cols-2 gap-4 pt-2">
          <div class="p-4 border border-gray-200 rounded-lg bg-gray-50">
            <p class="text-xs text-gray-500 uppercase tracking-wide">峰值销售额</p>
            <p class="text-lg font-medium text-gray-800">{{ formatCurrency(detail && detail.peak_revenue) }}</p>
            <p class="text-xs text-gray-400 mt-1">{{ formatDate(detail && detail.peak_revenue_date) }}</p>
          </div>
          <div class="p-4 border border-gray-200 rounded-lg bg-gray-50">
            <p class="text-xs text-gray-500 uppercase tracking-wide">峰值销量</p>
            <p class="text-lg font-medium text-gray-800">{{ detail && detail.peak_quantity != null ? detail.peak_quantity : '-' }}</p>
            <p class="text-xs text-gray-400 mt-1">{{ formatDate(detail && detail.peak_quantity_date) }}</p>
          </div>
        </div>
        <div class="p-4 border border-gray-200 rounded-lg bg-gray-50">
          <p class="text-xs text-gray-500 uppercase tracking-wide">当前阶段说明</p>
          <p class="text-sm text-gray-700">
            处于 <span class="font-medium">{{ currentStage }}</span>，已持续
            <span class="font-medium">{{ currentStageDurationDays }}</span> 天。
          </p>
          <p class="text-xs text-gray-600 mt-1">{{ detail && detail.details ? detail.details : '-' }}</p>
          <p v-if="detail && !detail.is_complete && detail.next_stage_prediction" class="text-xs text-blue-600 mt-1">下一阶段预测：{{ detail.next_stage_prediction }}</p>
        </div>
      </div>

      <!-- 阶段分析板块 -->
      <div class="lg:col-span-2 bg-white rounded-xl p-6 shadow-sm">
        <h3 class="text-lg font-semibold text-gray-800 mb-6">阶段分析</h3>
        <div class="overflow-x-auto">
          <table class="min-w-full divide-y divide-gray-200">
            <thead>
            <tr>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">阶段</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">总销售额</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">销售额占比</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">总销量</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">销量占比</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">日均销售额</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">日均销量</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">持续天数</th>
              <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">起止日期</th>
            </tr>
            </thead>
            <tbody class="bg-white divide-y divide-gray-200">
            <tr v-for="(stats, stage) in displayStageStats" :key="stage">
              <td class="px-4 py-3 text-sm"><span class="lifecycle-stage" :class="stageClass(stage)">{{ stage }}</span></td>
              <td class="px-4 py-3 text-sm font-medium text-gray-800">{{ formatCurrency(stats.totalRevenue) }}</td>
              <td class="px-4 py-3 text-sm text-gray-700">{{ formatPercent(stats.revenuePercentage) }}</td>
              <td class="px-4 py-3 text-sm font-medium text-gray-800">{{ stats.totalQuantity != null ? stats.totalQuantity : '-' }}</td>
              <td class="px-4 py-3 text-sm text-gray-700">{{ formatPercent(stats.quantityPercentage) }}</td>
              <td class="px-4 py-3 text-sm text-gray-700">{{ formatCurrency(stats.avgDailyRevenue) }}</td>
              <td class="px-4 py-3 text-sm text-gray-700">{{ stats.avgDailyQuantity != null ? stats.avgDailyQuantity : '-' }}</td>
              <td class="px-4 py-3 text-sm text-gray-700">{{ stats.durationDays }}</td>
              <td class="px-4 py-3 text-xs text-gray-600">{{ formatDate(stats.startDate) }} ~ {{ formatDate(stats.endDate) }}</td>
            </tr>
            </tbody>
          </table>
        </div>

        <!-- 对比条形图：各阶段 销售额/销量/持续天数 -->
        <div class="mt-8">
          <div class="flex justify-between items-center mb-4">
            <h4 class="text-base font-semibold text-gray-800">阶段对比条形图</h4>
            <div class="text-xs text-gray-500">销售额/销量/持续天数</div>
          </div>
          <div class="h-64">
            <canvas ref="stageCompareRef"></canvas>
          </div>
        </div>
      </div>
    </div>

    <!-- 完整性评估细则与权重 -->
    <div class="bg-white rounded-xl p-6 mb-20 shadow-sm">
      <div class="flex justify-between items-center mb-6">
        <h3 class="text-lg font-semibold text-gray-800">完整性评估细项</h3>
        <div class="text-sm" :class="detail && detail.is_complete ? 'text-green-600' : 'text-orange-600'">
          总分 {{ detail && detail.completeness_score != null ? detail.completeness_score : 0 }}/100
          <span class="ml-2">{{ detail && detail.is_complete ? '(已达完整标准80分)' : '(未达完整标准)' }}</span>
        </div>
      </div>
      <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        <div v-for="item in breakdownItems" :key="item.key" class="flex items-center justify-between border border-gray-200 rounded-lg px-4 py-3 bg-gray-50">
          <div class="flex items-center gap-3">
            <span :class="item.hit ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'" class="px-3 py-1 rounded-full text-xs font-medium">
              {{ item.hit ? '命中' : '未命中' }}
            </span>
            <span class="text-sm text-gray-800">{{ item.label }}</span>
          </div>
          <span class="text-xs text-gray-500 font-medium">权重 {{ item.weight }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { uploadAndAnalyze, getLifecycleResults } from '@/api/lifecycle'
import { analyzeSpuFile, getSpuResults } from '@/api/client'
import { getToken } from '@/utils/auth'
import { Chart } from 'chart.js'
import { formatCurrency, formatDate } from '../../../utils/format'

const stageOrder = ['引入期', '成长期', '成熟期', '衰退期']

export default {
  name: 'LifecycleSpuDetail',
  data() {
    return {
      trendChart: null,
      stageCompareChart: null,
      upload: {
        // 是否显示弹出层
        open: false,
        // 弹出层标题
        title: '',
        // 是否禁用上传
        isUploading: false,
        // 是否更新已经存在的文件
        updateSupport: 0,
        // 设置上传的请求头部
        headers: { Authorization: 'Bearer ' + getToken() },
        // 上传的地址
        url: process.env.VUE_APP_PYTHON_API + '/api/spu-lifecycle/upload',
        // 文件名称
        fileName: '',
        // 已选择文件名称
        pendingFileName: '',
        // 是否忽略文件选择改变
        ignoreFileChange: false,
      }
    }
  },
  computed: {
    hasResults() {
      return Object.keys(this.results || {}).length > 0
    },
    results() {
      const state = this.$store && this.$store.state && this.$store.state.spuAnalysis
      return (state && state.results) || {}
    },
    selectedSpu: {
      get() {
        const state = this.$store && this.$store.state && this.$store.state.spuAnalysis
        return (state && state.selectedSpu) || ''
      },
      set(value) {
        if (this.$store) {
          this.$store.dispatch('spuAnalysis/selectSpu', value)
        }
      }
    },
    spuOptions() {
      return Object.keys(this.results || {}).filter(k => k !== '_analysis_summary_')
    },
    detail() {
      return (this.results && this.selectedSpu && this.results[this.selectedSpu]) || null
    },
    currentStage() {
      return (this.detail && this.detail.current_stage) || '-'
    },
    currentStageDurationDays() {
      const detail = this.detail || {}
      const stats = detail.stage_statistics || {}
      const cs = detail.current_stage
      if (cs && stats[cs] && stats[cs].durationDays != null) return stats[cs].durationDays
      return '-'
    },
    stageStats() {
      const detail = this.detail || {}
      return detail.stage_statistics || {}
    },
    displayStageStats() {
      const detail = this.detail || {}
      const stats = this.stageStats || {}
      const revenue = detail.revenue_series || detail.smoothed_revenue || []
      const qty = detail.quantity_series || detail.smoothed_quantity || []
      const rawDates = detail.date_series || []
      const labels = rawDates.map(d => formatDate(d))

      if (detail.is_complete) {
        const boundaries = (detail.stage_boundaries || []).map(b => formatDate(b.date))
        const idxs = boundaries.map(d => labels.indexOf(d)).filter(i => i >= 0).sort((a, b) => a - b)
        if (idxs.length >= 3) {
          const ranges = [
            { name: stageOrder[0], start: 0, end: idxs[0] },
            { name: stageOrder[1], start: idxs[0], end: idxs[1] },
            { name: stageOrder[2], start: idxs[1], end: idxs[2] },
            { name: stageOrder[3], start: idxs[2], end: labels.length - 1 }
          ]
          const totalRev = revenue.reduce((s, v) => s + (Number(v) || 0), 0)
          const totalQ = qty.reduce((s, v) => s + (Number(v) || 0), 0)
          const built = {}
          ranges.forEach(r => {
            const revSum = revenue.slice(r.start, r.end + 1).reduce((s, v) => s + (Number(v) || 0), 0)
            const qtySum = qty.slice(r.start, r.end + 1).reduce((s, v) => s + (Number(v) || 0), 0)
            const days = Math.max(0, r.end - r.start + 1)
            built[r.name] = {
              totalRevenue: revSum,
              revenuePercentage: totalRev ? (revSum / totalRev * 100) : 0,
              totalQuantity: qtySum,
              quantityPercentage: totalQ ? (qtySum / totalQ * 100) : 0,
              avgDailyRevenue: days ? (revSum / days) : 0,
              avgDailyQuantity: days ? (qtySum / days) : 0,
              durationDays: days,
              startDate: rawDates[r.start],
              endDate: rawDates[r.end]
            }
          })
          return built
        }
        if (stageOrder.every(s => stats[s])) return stats
      }

      const actual = {}
      const keys = stageOrder.filter(s => stats[s]).concat(Object.keys(stats).filter(s => stageOrder.indexOf(s) === -1))
      keys.forEach(k => {
        const v = stats[k] || {}
        let duration = v.durationDays
        const sIdx = labels.indexOf(formatDate(v.startDate))
        const eIdx = labels.indexOf(formatDate(v.endDate))
        if (sIdx >= 0 && eIdx >= 0 && eIdx >= sIdx) {
          duration = Math.max(0, eIdx - sIdx + 1)
        }
        actual[k] = Object.assign({}, v, { durationDays: duration })
      })
      return actual
    },
    breakdownItems() {
      const detail = this.detail || {}
      const bd = detail.completion_details || {}
      const mapping = [
        { key: 'sufficient_time', label: '时间长度≥120天' },
        { key: 'reasonable_peak_position', label: '峰值位置25%-75%' },
        { key: 'significant_growth', label: '显著增长（额≥100% 或 量≥80%）' },
        { key: 'noticeable_decline', label: '明显衰退（额≤-35% 或 量≤-30%）' },
        { key: 'has_lifecycle_shape', label: '生命周期形状（额CV≥0.3 且 量CV≥0.25）' },
        { key: 'peak_significance', label: '峰值显著性（≥均值1.8x）' },
        { key: 'data_quality_check', label: '数据质量（长度≥120，峰值>0，增/退均出现）' },
        { key: 'cycle_completeness', label: '周期完整性（时间/峰值/增长/衰退/形状）' },
        { key: 'trend_consistency', label: '趋势一致性（增差≤0.8 或 退差≤0.4 或同向）' }
      ]
      return mapping.map(m => {
        const item = bd[m.key] || {}
        return {
          key: m.key,
          label: m.label,
          hit: !!item.hit,
          weight: item.weight != null ? item.weight : '-'
        }
      })
    },
    hasFourStages() {
      const stats = this.stageStats || {}
      return stageOrder.every(s => !!stats[s])
    },
    totalRevenue() {
      const detail = this.detail || {}
      if (detail.total_revenue != null) return detail.total_revenue
      return Object.values(this.stageStats || {}).reduce((s, v) => s + (v.totalRevenue || 0), 0)
    },
    totalQty() {
      const detail = this.detail || {}
      if (detail.total_quantity != null) return detail.total_quantity
      return Object.values(this.stageStats || {}).reduce((s, v) => s + (v.totalQuantity || 0), 0)
    },
    revenuePct() {
      return 100
    },
    qtyPct() {
      return 100
    }
  },
  mounted() {
    if (!Object.keys(this.results || {}).length) {
      this.getList()
    }
    if (!this.selectedSpu || !this.results[this.selectedSpu]) {
      const first = this.spuOptions[0] || ''
      if (first) this.$store.dispatch('spuAnalysis/selectSpu', first)
    }
    this.renderTrend()
    this.renderStageCompare()
  },
  beforeDestroy() {
    if (this.trendChart) this.trendChart.destroy()
    if (this.stageCompareChart) this.stageCompareChart.destroy()
  },
  watch: {
    detail() {
      this.renderTrend()
      this.renderStageCompare()
    },
    results() {
      if (!this.results || !this.results[this.selectedSpu]) {
        const first = this.spuOptions[0] || ''
        if (first) this.$store.dispatch('spuAnalysis/selectSpu', first)
      }
    }
  },
  methods: {
    /** 获取生命周期分析结果 */
    getList() {
      getSpuResults().then(response => {
        const payload = response && response.data ? response.data : null
        if (payload) {
          const results = payload || {}
          this.$store.commit('spuAnalysis/SET_RESULTS', results)
          const firstSpu = this.pickFirstSpu(results)
          this.$store.commit('spuAnalysis/SET_SELECTED_SPU', firstSpu)
          this.$nextTick(() => {
            this.renderTrend()
            this.renderStageCompare()
          })
        }
      }).catch(() => {
        this.$store.commit('spuAnalysis/SET_RESULTS', {})
      })
    },
    /** 文件选择改变处理 */
    handleFileChange(file, fileList) {
      if (this.upload.ignoreFileChange) return
      if (!fileList || fileList.length === 0) return
      if (!file || !file.raw) return

      this.upload.pendingFileName = file.name
      this.upload.fileName = ''
    },
    /** 文件上传前的校验 */
    beforeUpload(file) {
      const isExcel = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
        file.type === 'application/vnd.ms-excel' ||
        file.type === 'text/csv' ||
        file.name.endsWith('.xlsx') ||
        file.name.endsWith('.xls') ||
        file.name.endsWith('.csv')
      const isLt500M = file.size / 1024 / 1024 < 500

      if (!isExcel) {
        this.$modal.msgError('上传文件只能是 xlsx/xls/csv 格式!')
        return false
      }
      if (!isLt500M) {
        this.$modal.msgError('上传文件大小不能超过 500MB!')
        return false
      }
      return true
    },
    handleFileUploadProgress() {
      this.upload.isUploading = true
    },
    customUpload(options) {
      const file = options.file
      this.upload.isUploading = true
      analyzeSpuFile(file).then(response => {
        this.upload.isUploading = false
        if (response && response.success) {
          const results = response.data || {}
          this.$store.commit('spuAnalysis/SET_RESULTS', results)
          const firstSpu = this.pickFirstSpu(results)
          this.$store.commit('spuAnalysis/SET_SELECTED_SPU', firstSpu)
          this.$modal.msgSuccess('文件上传并分析成功')
          this.upload.fileName = this.upload.pendingFileName || file.name
          this.upload.pendingFileName = ''
          this.$nextTick(() => {
            this.renderTrend()
            this.renderStageCompare()
          })
          options.onSuccess(response)
        } else {
          this.$modal.msgError(response.msg || '分析失败')
          options.onError(new Error(response.msg || '分析失败'))
        }
      }).catch(error => {
        this.upload.isUploading = false
        const msg = (error && error.message) || '文件上传失败，请重试'
        this.$modal.msgError(msg)
        options.onError(error)
      }).finally(() => {
        if (this.$refs.toolbarUpload) {
          this.upload.ignoreFileChange = true
          this.$refs.toolbarUpload.clearFiles()
          this.$nextTick(() => {
            this.upload.ignoreFileChange = false
          })
        }
      })
    },
    submitUpload() {
      const target = this.$refs.toolbarUpload
      const fileList = target && target.uploadFiles ? target.uploadFiles : []
      if (!fileList || fileList.length === 0) {
        this.$modal.msgError('请选择要上传的文件')
        return
      }
      target.submit()
    },
    formatCurrency,
    formatDate,
    formatPercent(n) {
      if (n == null || Number.isNaN(n)) return '-'
      return String(Number(n).toFixed(1)) + '%'
    },
    stageClass(s) {
      if (!s) return ''
      if (s.indexOf('引入') >= 0 || s.indexOf('导入') >= 0) return 'intro'
      if (s.indexOf('成长') >= 0) return 'growth'
      if (s.indexOf('成熟') >= 0) return 'maturity'
      if (s.indexOf('衰退') >= 0) return 'decline'
      return ''
    },
    normalizeDate(dateStr) {
      if (!dateStr) return ''
      const match = String(dateStr).match(/(\d{4}-\d{2}-\d{2})/)
      if (match) return match[1]
      const parts = String(dateStr).split('T')
      return parts[0].split(' ')[0]
    },
    renderTrend() {
      const canvas = this.$refs.lifeCycleTrendRef
      if (!canvas) return
      const detail = this.detail || {}
      const revenue = detail.smoothed_revenue || detail.revenue_series || []
      const qty = detail.smoothed_quantity || detail.quantity_series || []
      const rawDates = detail.date_series || []
      const labels = rawDates.map(d => formatDate(d))
      const boundaries = (detail.stage_boundaries || []).map(b => ({
        type: b.type,
        date: b.date ? formatDate(b.date) : null,
        index: b.index
      }))

      const stageColors = {
        [stageOrder[0]]: 'rgba(59,130,246,0.08)',
        [stageOrder[1]]: 'rgba(16,185,129,0.10)',
        [stageOrder[2]]: 'rgba(245,158,11,0.10)',
        [stageOrder[3]]: 'rgba(239,68,68,0.08)'
      }

      const segments = []
      const stagesMap = detail.stages_map || []

      console.log('renderTrend - stagesMap length:', stagesMap.length, 'labels length:', labels.length)
      console.log('renderTrend - stagesMap sample:', stagesMap.slice(0, 10))
      console.log('renderTrend - is_complete:', detail.is_complete)
      console.log('renderTrend - stage_boundaries:', detail.stage_boundaries)

      if (stagesMap.length > 0 && stagesMap.length === labels.length) {
        let currentStage = stagesMap[0]
        let segmentStart = 0

        for (let i = 1; i < stagesMap.length; i++) {
          if (stagesMap[i] !== currentStage) {
            if (currentStage && stageColors[currentStage]) {
              segments.push({
                start: segmentStart,
                end: i - 1,
                stage: currentStage
              })
            }
            currentStage = stagesMap[i]
            segmentStart = i
          }
        }
        if (currentStage && stageColors[currentStage] && segmentStart < stagesMap.length) {
          segments.push({
            start: segmentStart,
            end: stagesMap.length - 1,
            stage: currentStage
          })
        }
      } else {
        const statsObj = this.displayStageStats || {}
        const orderedNames = stageOrder.filter(s => statsObj[s]).concat(Object.keys(statsObj).filter(s => stageOrder.indexOf(s) === -1))
        orderedNames.forEach(name => {
          const sIdx = labels.indexOf(formatDate(statsObj[name] && statsObj[name].startDate))
          const eIdx = labels.indexOf(formatDate(statsObj[name] && statsObj[name].endDate))
          if (sIdx >= 0 && eIdx >= 0 && eIdx >= sIdx) {
            segments.push({ start: sIdx, end: eIdx, stage: name })
          }
        })
      }

      console.log('renderTrend - segments:', segments)

      const peakRevenueDateRaw = detail.peak_revenue_date
      const peakQuantityDateRaw = detail.peak_quantity_date

      let peakRevIdx = -1
      let peakQtyIdx = -1

      if (peakRevenueDateRaw && rawDates.length > 0) {
        const targetDate = this.normalizeDate(peakRevenueDateRaw)
        peakRevIdx = rawDates.findIndex(d => this.normalizeDate(d) === targetDate)

        if (peakRevIdx < 0 && detail.revenue_peak_idx != null) {
          const backendIdx = detail.revenue_peak_idx
          if (backendIdx >= 0 && backendIdx < rawDates.length) {
            peakRevIdx = backendIdx
          }
        }
      }

      if (peakQuantityDateRaw && rawDates.length > 0) {
        const targetDate = this.normalizeDate(peakQuantityDateRaw)
        peakQtyIdx = rawDates.findIndex(d => this.normalizeDate(d) === targetDate)

        if (peakQtyIdx < 0 && detail.quantity_peak_idx != null) {
          const backendIdx = detail.quantity_peak_idx
          if (backendIdx >= 0 && backendIdx < rawDates.length) {
            peakQtyIdx = backendIdx
          }
        }
      }

      const boundaryIndices = []
      if (boundaries && boundaries.length > 0) {
        boundaries.forEach(b => {
          let idx = -1

          if (b.index != null && b.index >= 0 && b.index < rawDates.length) {
            idx = b.index
          } else if (b.date) {
            const targetDate = this.normalizeDate(b.date)
            idx = rawDates.findIndex(d => this.normalizeDate(d) === targetDate)
          }

          if (idx >= 0 && idx < rawDates.length) {
            boundaryIndices.push({ index: idx, type: b.type })
          }
        })
      }

      if (this.trendChart) this.trendChart.destroy()
      this.trendChart = new Chart(canvas, {
        type: 'line',
        data: {
          labels: labels,
          datasets: [
            {
              label: '销售额',
              data: revenue,
              borderColor: '#3b82f6',
              backgroundColor: 'rgba(59,130,246,0.15)',
              lineTension: 0.25,
              pointRadius: 0,
              pointHoverRadius: 6,
              pointHoverBackgroundColor: '#3b82f6',
              pointHoverBorderColor: '#ffffff',
              pointHoverBorderWidth: 2
            },
            {
              label: '销量',
              data: qty,
              borderColor: '#64748b',
              backgroundColor: 'rgba(100,116,139,0.15)',
              lineTension: 0.25,
              pointRadius: 0,
              pointHoverRadius: 6,
              pointHoverBackgroundColor: '#64748b',
              pointHoverBorderColor: '#ffffff',
              pointHoverBorderWidth: 2
            }
          ]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          tooltips: {
            enabled: true,
            backgroundColor: 'rgba(0,0,0,0.8)',
            titleFontColor: '#ffffff',
            bodyFontColor: '#ffffff',
            borderColor: '#374151',
            borderWidth: 1,
            cornerRadius: 6,
            displayColors: true,
            callbacks: {
              title: function(context) {
                return '日期: ' + context[0].label
              },
              label: function(context, data) {
                const datasetLabel = data.datasets[context.datasetIndex].label
                const value = context.value
                return datasetLabel + ': ' + Number(value).toLocaleString()
              }
            }
          },
          hover: {
            mode: 'index',
            intersect: false
          },
          scales: {
            xAxes: [{
              ticks: {
                maxRotation: 0,
                autoSkip: true,
                maxTicksLimit: 12,
                callback: function(value, index) {
                  return labels[index]
                }
              }
            }]
          }
        },
        plugins: [{
          id: 'stage-backgrounds',
          beforeDatasetsDraw(chart) {
            const ctx = chart.ctx
            const chartArea = chart.chartArea
            const xScale = chart.scales['x-axis-0']

            console.log('stage-backgrounds plugin - segments:', segments)
            console.log('stage-backgrounds plugin - chartArea:', chartArea)

            if (!segments.length) {
              console.log('stage-backgrounds plugin - no segments to draw')
              return
            }

            ctx.save()
            segments.forEach((seg, idx) => {
              const x1 = xScale.getPixelForValue(seg.start)
              const x2 = xScale.getPixelForValue(seg.end)
              const color = stageColors[seg.stage] || 'rgba(0,0,0,0.04)'

              console.log('Drawing segment ' + idx + ': ' + seg.stage + ', start=' + seg.start + '(' + x1 + 'px), end=' + seg.end + '(' + x2 + 'px), color=' + color)

              ctx.fillStyle = color
              ctx.fillRect(x1, chartArea.top, x2 - x1, chartArea.bottom - chartArea.top)

              ctx.fillStyle = '#374151'
              ctx.font = 'bold 12px sans-serif'
              ctx.textAlign = 'left'
              ctx.fillText(seg.stage, x1 + 4, chartArea.top + 14)
            })
            ctx.restore()
          }
        }, {
          id: 'stage-markers',
          afterDatasetsDraw(chart) {
            const ctx = chart.ctx
            const chartArea = chart.chartArea
            const xScale = chart.scales['x-axis-0']
            const yScale = chart.scales['y-axis-0']
            ctx.save()

            if (boundaryIndices.length > 0) {
              boundaryIndices.forEach(boundary => {
                const x = xScale.getPixelForValue(boundary.index)

                ctx.strokeStyle = '#ef4444'
                ctx.setLineDash([8, 4])
                ctx.lineWidth = 2
                ctx.beginPath()
                ctx.moveTo(x, chartArea.top)
                ctx.lineTo(x, chartArea.bottom)
                ctx.stroke()
                ctx.setLineDash([])

                const labelText = boundary.type
                const labelWidth = ctx.measureText(labelText).width + 8
                const labelHeight = 16
                const labelX = x - labelWidth / 2
                const labelY = chartArea.top + 8

                ctx.fillStyle = 'rgba(239, 68, 68, 0.1)'
                ctx.fillRect(labelX, labelY, labelWidth, labelHeight)

                ctx.strokeStyle = '#ef4444'
                ctx.lineWidth = 1
                ctx.strokeRect(labelX, labelY, labelWidth, labelHeight)

                ctx.fillStyle = '#ef4444'
                ctx.font = 'bold 11px sans-serif'
                ctx.textAlign = 'center'
                ctx.fillText(labelText, x, labelY + 12)
              })
            }

            if (peakRevIdx >= 0 && peakRevIdx < revenue.length && revenue[peakRevIdx] != null) {
              const x = xScale.getPixelForValue(peakRevIdx)
              const y = yScale.getPixelForValue(revenue[peakRevIdx])

              ctx.fillStyle = '#dc2626'
              ctx.beginPath()
              ctx.arc(x, y, 5, 0, Math.PI * 2)
              ctx.fill()

              ctx.strokeStyle = '#ffffff'
              ctx.lineWidth = 2
              ctx.stroke()

              ctx.fillStyle = '#dc2626'
              ctx.font = 'bold 12px sans-serif'
              ctx.textAlign = 'left'
              ctx.fillText('销售额峰值', x + 10, y - 10)

              ctx.font = '11px sans-serif'
              ctx.fillText('￥' + Number(revenue[peakRevIdx]).toLocaleString(), x + 10, y + 2)
            }

            if (peakQtyIdx >= 0 && peakQtyIdx < qty.length && qty[peakQtyIdx] != null) {
              const x = xScale.getPixelForValue(peakQtyIdx)
              const y = yScale.getPixelForValue(qty[peakQtyIdx])

              ctx.fillStyle = '#2563eb'
              ctx.beginPath()
              ctx.arc(x, y, 5, 0, Math.PI * 2)
              ctx.fill()

              ctx.strokeStyle = '#ffffff'
              ctx.lineWidth = 2
              ctx.stroke()

              ctx.fillStyle = '#2563eb'
              ctx.font = 'bold 12px sans-serif'
              ctx.textAlign = 'left'
              ctx.fillText('销量峰值', x + 10, y - 10)

              ctx.font = '11px sans-serif'
              ctx.fillText(String(qty[peakQtyIdx]).toLocaleString() + '件', x + 10, y + 2)
            }
            ctx.restore()
          }
        }]
      })
    },
    renderStageCompare() {
      const canvas = this.$refs.stageCompareRef
      if (!canvas) return
      const stats = this.displayStageStats || {}
      const orderedStages = stageOrder.filter(s => stats[s]).concat(Object.keys(stats).filter(s => stageOrder.indexOf(s) === -1))
      const labels = orderedStages
      const revenueData = labels.map(s => (stats[s] && stats[s].totalRevenue) || 0)
      const qtyData = labels.map(s => (stats[s] && stats[s].totalQuantity) || 0)
      const durationData = labels.map(s => (stats[s] && stats[s].durationDays) || 0)

      if (this.stageCompareChart) this.stageCompareChart.destroy()
      this.stageCompareChart = new Chart(canvas, {
        type: 'bar',
        data: {
          labels: labels,
          datasets: [
            { label: '销售额', data: revenueData, backgroundColor: 'rgba(59,130,246,0.7)' },
            { label: '销量', data: qtyData, backgroundColor: 'rgba(16,185,129,0.7)' },
            { label: '持续天数', data: durationData, backgroundColor: 'rgba(245,158,11,0.7)' }
          ]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          scales: {
            xAxes: [{ stacked: false }],
            yAxes: [{ ticks: { beginAtZero: true } }]
          }
        }
      })
    },
    formatUploadDate(date) {
      const d = date instanceof Date ? date : new Date(date)
      if (Number.isNaN(d.getTime())) return ''
      const y = d.getFullYear()
      const m = String(d.getMonth() + 1).padStart(2, '0')
      const day = String(d.getDate()).padStart(2, '0')
      return `${y}-${m}-${day}`
    },
    exportResults() {
      if (!this.hasResults) {
        this.$modal.msgError('暂无可导出的分析结果')
        return
      }
      const payload = JSON.stringify(this.results || {}, null, 2)
      const blob = new Blob([payload], { type: 'application/json;charset=utf-8' })
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = `spu_lifecycle_results_${this.formatUploadDate(new Date())}.json`
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      URL.revokeObjectURL(url)
    },
    pickFirstSpu(obj) {
      const keys = Object.keys(obj || {})
      const first = keys.find(k => k !== '_analysis_summary_')
      return first || ''
    }
  }
}
</script>

<style scoped lang="scss">
.app-container {
  padding: 20px;
}

.page-header {
  margin-bottom: 20px;

  h2 {
    font-size: 24px;
    font-weight: 600;
    color: #303133;
    margin-bottom: 8px;

    i {
      margin-right: 8px;
      color: #409EFF;
    }
  }

  .page-desc {
    color: #909399;
    font-size: 14px;
    margin: 0;
  }
}

.mb-20 { margin-bottom: 20px; }

.upload-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #ffffff;
  border: 1px solid #e6eaf2;
  border-radius: 8px;
  padding: 12px 16px;
  margin-bottom: 16px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.toolbar-upload ::v-deep .el-upload {
  display: inline-flex;
}

.toolbar-status {
  font-size: 13px;
  color: #16a34a;
  background: #f0fdf4;
  border: 1px solid #dcfce7;
  border-radius: 6px;
  padding: 6px 10px;
}

.toolbar-status.muted {
  color: #6b7280;
  background: #f8fafc;
  border-color: #e2e8f0;
}
.p-6 { padding: 24px; }
.p-4 { padding: 16px; }
.px-3 { padding-left: 12px; padding-right: 12px; }
.px-4 { padding-left: 16px; padding-right: 16px; }
.py-1 { padding-top: 4px; padding-bottom: 4px; }
.py-2 { padding-top: 8px; padding-bottom: 8px; }
.py-3 { padding-top: 12px; padding-bottom: 12px; }
.pt-2 { padding-top: 8px; }
.mb-2 { margin-bottom: 8px; }
.mb-4 { margin-bottom: 16px; }
.mb-6 { margin-bottom: 24px; }
.mb-8 { margin-bottom: 32px; }
.mt-1 { margin-top: 4px; }
.mt-4 { margin-top: 16px; }
.mt-8 { margin-top: 32px; }
.ml-2 { margin-left: 8px; }
.mr-1 { margin-right: 4px; }

.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.gap-4 { gap: 16px; }
.gap-8 { gap: 20px; }

.grid { display: grid; }
.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.lg\:col-span-2 { grid-column: span 2 / span 2; }
.overflow-x-auto { overflow-x: auto; }
.min-w-full { min-width: 100%; }

.text-3xl { font-size: 22px; line-height: 1.3; }
.text-base { font-size: 16px; line-height: 1.5; }
.text-lg { font-size: 18px; line-height: 1.5; }
.text-sm { font-size: 14px; line-height: 1.5; }
.text-xs { font-size: 12px; line-height: 1.4; }
.font-bold { font-weight: 700; }
.font-semibold { font-weight: 600; }
.font-medium { font-weight: 500; }
.text-left { text-align: left; }
.uppercase { text-transform: uppercase; }
.tracking-wide { letter-spacing: 0.04em; }
.tracking-wider { letter-spacing: 0.06em; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.text-gray-900 { color: #111827; }
.text-gray-800 { color: #303133; }
.text-gray-700 { color: #606266; }
.text-gray-600 { color: #909399; }
.text-gray-500 { color: #909399; }
.text-gray-400 { color: #9ca3af; }
.text-blue-600 { color: #2563eb; }
.text-green-700 { color: #15803d; }
.text-green-600 { color: #16a34a; }
.text-red-700 { color: #b91c1c; }
.text-red-600 { color: #dc2626; }
.text-orange-600 { color: #ea580c; }
.text-yellow-800 { color: #92400e; }

.bg-white { background: #ffffff; }
.bg-gray-50 { background: #f9fafb; }
.bg-gray-500 { background: #6b7280; }
.bg-blue-500 { background: #3b82f6; }
.bg-green-100 { background: #dcfce7; }
.bg-red-100 { background: #fee2e2; }

.bg-gradient-to-r { background-image: linear-gradient(to right, var(--from-color), var(--to-color)); }
.from-yellow-100 { --from-color: #fef9c3; }
.to-amber-100 { --to-color: #fef3c7; }

.border { border-width: 1px; border-style: solid; }
.border-gray-200 { border-color: #e5e7eb; }
.border-gray-300 { border-color: #d1d5db; }
.rounded-xl { border-radius: 8px; }
.rounded-lg { border-radius: 10px; }
.rounded-full { border-radius: 9999px; }
.shadow-sm { border: 1px solid #e6eaf2; box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06); }

.h-96 { height: 400px; }
.h-64 { height: 256px; }
.w-3 { width: 12px; }
.h-3 { height: 12px; }

.space-y-2 > * + * { margin-top: 8px; }
.space-y-6 > * + * { margin-top: 24px; }
.divide-y > * + * { border-top: 1px solid #e5e7eb; }
.divide-gray-200 > * + * { border-top-color: #e5e7eb; }

.focus\:outline-none:focus { outline: none; }
.focus\:border-transparent:focus { border-color: transparent; }
.focus\:ring-2:focus { box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.35); }
.focus\:ring-blue-500:focus { box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.45); }

.spu-select {
  min-width: 200px;
  background: #ffffff;
}

table {
  border-collapse: separate;
  border-spacing: 0;
}

thead tr {
  background: #f8fafc;
}

thead th:first-child {
  border-top-left-radius: 8px;
}

thead th:last-child {
  border-top-right-radius: 8px;
}

@media (min-width: 768px) {
  .md\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .lg\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* 进度条基础样式 */
.progress-bar { height: 8px; background: #f3f4f6; border-radius: 999px; overflow: hidden; }
.progress-value { height: 100%; border-radius: 999px; }

/* 阶段标签色块 */
.lifecycle-stage { padding: 2px 8px; border-radius: 999px; font-size: 12px; }
.lifecycle-stage.intro { background: #dbeafe; color: #1e40af; }
.lifecycle-stage.growth { background: #dcfce7; color: #166534; }
.lifecycle-stage.maturity { background: #fef3c7; color: #92400e; }
.lifecycle-stage.decline { background: #fee2e2; color: #991b1b; }
</style>
