<template>
  <div class="chart-container">
    <canvas ref="canvas"></canvas>
  </div>
</template>

<script>
import { getAllDecisions } from '../lib/dataCache'
import { readAllRawDecisions } from '../lib/idb'
import { filterRowsToNyseTradingDays } from '../lib/marketCalendar'
import { STRATEGIES } from '../lib/strategies'
import { computeBuyHoldEquity, computeStrategyEquity } from '../lib/perf'
import { Chart, LineElement, PointElement, LinearScale, CategoryScale, LineController, Legend, Tooltip } from 'chart.js'
import { getStrategyColor } from '../lib/chartColors'

const vLinePlugin = {
  id: 'vLinePlugin',
  afterDatasetsDraw(chart, args, pluginOptions) {
    const active = (typeof chart.getActiveElements === 'function') ? chart.getActiveElements() : (chart.tooltip && chart.tooltip._active) || []
    if (!active || !active.length) return
    const { datasetIndex, index } = active[0]
    const meta = chart.getDatasetMeta(datasetIndex)
    const pt = meta && meta.data && meta.data[index]
    if (!pt) return
    const x = pt.x
    const { top, bottom } = chart.chartArea
    const ctx = chart.ctx
    ctx.save()
    ctx.beginPath()
    ctx.moveTo(x, top)
    ctx.lineTo(x, bottom)
    ctx.lineWidth = (pluginOptions && pluginOptions.lineWidth) || 1
    ctx.strokeStyle = (pluginOptions && pluginOptions.color) || 'rgba(0,0,0,0.35)'
    ctx.setLineDash((pluginOptions && pluginOptions.dash) || [4, 4])
    ctx.stroke()
    ctx.restore()
  }
}

Chart.register(LineElement, PointElement, LinearScale, CategoryScale, LineController, Legend, Tooltip, vLinePlugin)

export default {
  name: 'CompareChart',
  props: {
    selected: { type: Array, default: () => [] },
    visible: { type: Boolean, default: false }
  },
  data(){
    return { chart: null, datasets: [], labels: [] }
  },
  watch: {
    visible(v){ if (v) { this.$nextTick(() => this.buildAndDraw()) } },
    selected: { deep: true, handler(){ this.buildAndDraw() } }
  },
  mounted(){ this.$nextTick(() => this.buildAndDraw()) },
  beforeUnmount(){ try{ this.chart && this.chart.destroy() }catch(_){} },
  methods: {
    async buildAndDraw(){
      if (!this.visible) return
      await this.rebuildDatasetsFromSelection()
      this.draw()
    },
    async getAll(){
      let all = getAllDecisions() || []
      if (!all.length) {
        try { const cached = await readAllRawDecisions(); if (cached && cached.length) all = cached } catch(_) {}
      }
      return all
    },
    async rebuildDatasetsFromSelection(){
      const selected = Array.isArray(this.selected) ? this.selected : []
      const all = await this.getAll()
      const groupKeyToSeq = new Map()
      for (const sel of selected) {
        const agent = sel.agent_name
        const asset = sel.asset
        const model = sel.model
        const ids = Array.isArray(sel.decision_ids) ? sel.decision_ids : []
        let seq = []
        if (ids.length) seq = all.filter(r => ids.includes(r.id))
        else seq = all.filter(r => r.agent_name === agent && r.asset === asset && r.model === model)
        seq.sort((a,b) => (a.date > b.date ? 1 : -1))
        const isCrypto = asset === 'BTC' || asset === 'ETH'
        const filtered = isCrypto ? seq : await filterRowsToNyseTradingDays(seq)
        groupKeyToSeq.set(`${agent}|${asset}|${model}`, filtered)
      }

      const ds = []
      const keys = Array.from(groupKeyToSeq.keys())
      // labels from first sequence
      this.labels = []
      if (keys.length) this.labels = (groupKeyToSeq.get(keys[0]) || []).map(s => s.date)

      // 按 agent 分组以应用颜色规则
      const agentGroups = new Map() // agent -> [selection items]
      const selectedAssets = new Set()
      
      for (const sel of selected) {
        const gk = `${sel.agent_name}|${sel.asset}|${sel.model}`
        const seq = groupKeyToSeq.get(gk) || []
        if (!seq.length) continue
        
        selectedAssets.add(sel.asset)
        const agent = sel.agent_name
        if (!agentGroups.has(agent)) {
          agentGroups.set(agent, [])
        }
        agentGroups.get(agent).push({ sel, seq })
      }

      // 为每个 agent 的策略生成系列，同一 agent 使用相同色调
      for (const [agent, items] of agentGroups.entries()) {
        items.forEach((item, index) => {
          const { sel, seq } = item
          const cfg = (STRATEGIES || []).find(s => s.id === sel.strategy) || { 
            strategy: 'long_short', 
            tradingMode: 'normal', 
            fee: 0.0005, 
            label: 'Selected' 
          }
          const series = computeStrategyEquity(seq, 100000, cfg.fee, cfg.strategy, cfg.tradingMode)
          if (!series.length) return
          
          // 同一 agent 的策略使用相同色调，通过亮度区分
          const strategyColor = getStrategyColor(agent, false, index)
          
          ds.push({
            label: `${sel.agent_name}|${sel.asset}|${sel.model}|${cfg.label || sel.strategy || 'Strategy'}`,
            data: this.labels.length ? series.slice(0, this.labels.length) : series,
            borderColor: strategyColor,
            pointRadius: 0,
            tension: 0.15
          })
        })
      }
      
      // 为每个资产添加 baseline，统一使用黑色实线
      const seenAsset = new Set()
      for (const gk of keys) {
        const asset = gk.split('|')[1]
        if (!selectedAssets.has(asset)) continue
        if (seenAsset.has(asset)) continue
        seenAsset.add(asset)
        const seq = groupKeyToSeq.get(gk) || []
        const bh = computeBuyHoldEquity(seq, 100000)
        if (!bh.length) continue
        
        // baseline 统一使用黑色实线
        const baselineColor = getStrategyColor('', true, 0)
        
        ds.push({
          label: `${asset} · Buy&Hold`,
          data: this.labels.length ? bh.slice(0, this.labels.length) : bh,
          borderColor: baselineColor,
          borderWidth: 1.5,
          pointRadius: 0,
          tension: 0
        })
      }
      this.datasets = ds
    },
    draw(){
      if (!this.$refs.canvas) return
      this.$nextTick(() => {
        if (!this.$refs.canvas) return
        try{ this.chart && this.chart.destroy() }catch(_){}
        const parent = this.$refs.canvas.parentElement
        if (parent) {
          if (!parent.clientHeight || parent.clientHeight < 50) { parent.style.minHeight = '560px'; parent.style.height = '560px' }
          const w = parent.clientWidth || 800
          const h = parent.clientHeight || 560
          this.$refs.canvas.style.width = '100%'
          this.$refs.canvas.style.height = '100%'
          this.$refs.canvas.width = w
          this.$refs.canvas.height = h
        }
        const labels = this.labels.length ? this.labels : Array.from({ length: Math.max(0, ...this.datasets.map(d => (Array.isArray(d.data) ? d.data.length : 0))) }, (_, i) => `${i+1}`)
        const allValues = this.datasets.flatMap(d => (Array.isArray(d.data) ? d.data : []))
        const minV = allValues.length ? Math.min(...allValues) : 0
        const maxV = allValues.length ? Math.max(...allValues) : 1
        const pad = (maxV - minV) * 0.1 || 1000
        const yMin = minV - pad
        const yMax = maxV + pad
        const ctx = this.$refs.canvas.getContext('2d')
        this.chart = new Chart(ctx, {
          type: 'line',
          data: { labels, datasets: this.datasets },
          options: {
            responsive: true,
            maintainAspectRatio: false,
            animation: false,
            interaction: { mode: 'index', intersect: false },
            plugins: {
              legend: { display: true, position: 'left', labels: { usePointStyle: true, boxWidth: 8 } },
              vLinePlugin: { color: 'rgba(0,0,0,0.35)', lineWidth: 1, dash: [4,4] }
            },
            scales: { x: { type: 'category', ticks: { autoSkip: true, maxTicksLimit: 10 } }, y: { min: yMin, max: yMax } }
          }
        })
      })
    }
  }
}
</script>

<style scoped>
.chart-container { position: relative; height: 560px; display: flex; }
.chart-container > canvas { width: 100% !important; height: 100% !important; }
</style>


