<template>
  <div class="p-4 flex flex-column gap-3">
    <div class="flex align-items-center justify-content-between mb-2">
      <div class="flex align-items-center gap-2">
        <Button label="← Back" class="p-button-outlined" size="small" rounded @click="$router.back()" />
        <div class="text-500 ml-2">Last updated: {{ lastUpdatedDisplay }}</div>
      </div>
    </div>

    <div v-if="loading" class="loading-overlay">
      <div class="loading-box">
        <ProgressSpinner />
        <div class="mt-3 text-600">Loading Equity Curves...</div>
      </div>
    </div>

    <Card class="card-full">
      <template #title>
        <div class="mb-2 text-900" style="font-size: 20px; font-weight: 600">Equity Curve Comparison</div>
        <Divider />
      </template>
      <template #content>
        <div class="chart-container">
          <canvas ref="canvas"></canvas>
        </div>
      </template>
    </Card>
  </div>
  
</template>

<script>
import { supabase } from '../lib/supabase'
import { getAllDecisions, setAllDecisions } from '../lib/dataCache'
import { writeRawDecisions, clearAllStores, 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, TimeScale, CategoryScale, LineController, Legend, Tooltip } from 'chart.js'

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, TimeScale, CategoryScale, LineController, Legend, Tooltip, vLinePlugin)

function color(i) {
  const colors = ['#3b82f6', '#22c55e', '#ef4444', '#a855f7', '#f59e0b', '#06b6d4', '#16a34a', '#f97316', '#0ea5e9', '#d946ef']
  return colors[i % colors.length]
}

export default {
  name: 'EquityComparison',
  components: { },
  data() {
    return {
      loading: true,
      lastUpdated: null,
      groupSeqMap: new Map(),
      datasets: [],
      chart: null,
      labels: []
    }
  },
  computed: {
    lastUpdatedDisplay() {
      return this.lastUpdated ? new Date(this.lastUpdated).toLocaleString() : '-'
    }
  },
  watch: {},
  methods: {
    async forceRefresh(){
      this.loading = true
      try { await clearAllStores() } catch(_) {}
      await this.load(true)
    },
    async load(forceRemote = false) {
      this.loading = true
      let all = (!forceRemote ? getAllDecisions() : null)
      if (!all && !forceRemote) {
        try {
          const cached = await readAllRawDecisions()
          if (cached && cached.length) {
            all = cached
            setAllDecisions(all)
          }
        } catch(_) {}
      }
      if (!all) {
        console.log('[EquityComparison] pulling all from remote...')
        const pageSize = 1000
        let from = 0
        all = []
        while (true) {
          const to = from + pageSize - 1
          const { data, error } = await supabase
            .from('trading_decisions')
            .select('id, agent_name, asset, model, date, price, recommended_action')
            .order('updated_at', { ascending: false })
            .range(from, to)
          if (error) { console.error(error); break }
          all = all.concat(data || [])
          if (!data || data.length < pageSize) break
          from += pageSize
        }
        setAllDecisions(all)
        try { await writeRawDecisions(all) } catch(_) {}
      }
      console.log('[EquityComparison] all decisions size:', (all || []).length)

      // 构建每个 (name|asset|model) 的时间序列（按资产处理交易日）
      const keyToSeq = new Map()
      const groups = new Map()
      for (const row of all) {
        if (row.price == null || !row.date) continue
        const key = `${row.agent_name}|${row.asset}|${row.model}`
        if (!groups.has(key)) groups.set(key, [])
        groups.get(key).push(row)
      }
      console.log('[EquityComparison] groups count:', groups.size)
      for (const [key, list] of groups.entries()) {
        list.sort((a,b) => (a.date > b.date ? 1 : -1))
        const asset = list[0]?.asset
        const isCrypto = asset === 'BTC' || asset === 'ETH'
        const seq = isCrypto ? list : (await filterRowsToNyseTradingDays(list))
        keyToSeq.set(key, seq)
      }
      this.groupSeqMap = keyToSeq

      // 根据 Home 中选择的行构建数据集（内部会在数据就绪后触发 draw）
      this.rebuildDatasetsFromSelection()
      this.lastUpdated = Date.now()
      this.loading = false
    },
    rebuildDatasetsFromSelection(){
      const ds = []
      let selected = []
      try { selected = JSON.parse(sessionStorage.getItem('compareRows') || '[]') } catch(_) {}
      if (!Array.isArray(selected)) selected = []
      console.log('[EquityComparison] compareRows:', selected)

      const all = getAllDecisions() || []
      console.log('[EquityComparison] getAllDecisions size:', all.length)

      // Build sequences using PerformanceChart's approach: use decision_ids first, else fallback triple key
      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)
        }
        console.log('[EquityComparison] seq len (before filter)', `${agent}|${asset}|${model}`, seq.length)
        seq.sort((a,b) => (a.date > b.date ? 1 : -1))
        const isCrypto = asset === 'BTC' || asset === 'ETH'
        const filteredSeqPromise = isCrypto ? Promise.resolve(seq) : filterRowsToNyseTradingDays(seq)
        groupKeyToSeq.set(`${agent}|${asset}|${model}`, filteredSeqPromise)
      }

      // Resolve any pending filtered sequences (stocks)
      const entries = Array.from(groupKeyToSeq.entries())
      // Await all promises for stock filtering
      // Note: some entries hold raw arrays (crypto), unify via Promise.resolve
      Promise.all(entries.map(([k, v]) => (Array.isArray(v) ? Promise.resolve([k, v]) : v.then(arr => [k, arr])))).then(resolved => {
        const resolvedMap = new Map(resolved)
        console.log('[EquityComparison] resolved groups:', Array.from(resolvedMap.keys()))
        console.log('[EquityComparison] resolved sizes:', Array.from(resolvedMap.entries()).map(([k,v]) => [k, v.length]))
        // Construct datasets per selected row with strategy from STRATEGIES matching sel.strategy
        let lineIndex = 0
        const selectedAssets = new Set()
        // build labels from the first resolved sequence's dates
        this.labels = []
        if (selected && selected.length) {
          const first = selected[0]
          const gk0 = `${first.agent_name}|${first.asset}|${first.model}`
          const seq0 = resolvedMap.get(gk0) || []
          this.labels = (seq0 || []).map(s => s.date)
        }
        for (const sel of selected) {
          const agent = sel.agent_name
          const asset = sel.asset
          const model = sel.model
          const gk = `${agent}|${asset}|${model}`
          const seq = resolvedMap.get(gk) || []
          if (!seq.length) continue
          selectedAssets.add(asset)
          // Pick strategy by sel.strategy id; if empty, default long_short normal
          const strategyCfg = (STRATEGIES || []).find(s => s.id === sel.strategy) || { strategy: 'long_short', tradingMode: 'normal', fee: 0.0005, label: 'Selected' }
          const series = computeStrategyEquity(seq, 100000, strategyCfg.fee, strategyCfg.strategy, strategyCfg.tradingMode)
          console.log('[EquityComparison] series len', gk, strategyCfg.id || strategyCfg.label, series.length)
          if (!series || series.length === 0) continue
          ds.push({
            label: `${agent}|${asset}|${model}|${strategyCfg.label || sel.strategy || 'Strategy'}`,
            data: this.labels && this.labels.length ? series.slice(0, this.labels.length) : series,
            borderColor: color(lineIndex++),
            pointRadius: 0,
            tension: 0.15
          })
        }

        // Add one Buy&Hold per selected asset
        const seenAsset = new Set()
        for (const [gk, seq] of resolvedMap.entries()) {
          const asset = gk.split('|')[1]
          if (!selectedAssets.has(asset)) continue
          if (seenAsset.has(asset)) continue
          seenAsset.add(asset)
          const bh = computeBuyHoldEquity(seq, 100000)
          console.log('[EquityComparison] baseline len', asset, bh.length)
          if (!bh || bh.length === 0) continue
          ds.push({
            label: `${asset} · Buy&Hold`,
            data: this.labels && this.labels.length ? bh.slice(0, this.labels.length) : bh,
            borderColor: color(lineIndex++),
            borderDash: [6, 4],
            borderWidth: 1.5,
            pointRadius: 0,
            tension: 0
          })
        }

        this.datasets = ds
        console.log('[EquityComparison] datasets count:', ds.length)
        this.draw()
      })
    },
    draw(){
      if (!this.$refs.canvas) return
      this.$nextTick(() => {
        if (!this.$refs.canvas) return
        if (this.chart) { try{ this.chart.destroy() }catch(_){}; this.chart = null }
        // ensure canvas sized to container
        try {
          const parent = this.$refs.canvas.parentElement
          if (parent) {
            // ensure parent has non-zero height even inside Card
            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
          }
        } catch(_) {}

        // use previously computed date labels; fallback to indices
        let labels = Array.isArray(this.labels) && this.labels.length ? this.labels : []
        if (!labels.length) {
          const maxLen = Math.max(0, ...this.datasets.map(d => (Array.isArray(d.data) ? d.data.length : 0)))
          labels = Array.from({ length: maxLen }, (_, 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 }
            }
          }
        })
      })
    }
  },
  mounted() { this.load() }
}
</script>

<style scoped>
.loading-overlay {
  position: fixed;
  inset: 0;
  background: rgba(255, 255, 255, 0.85);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
}
.loading-box { text-align: center; }

.chart-container {
  position: relative;
  height: 560px;
  display: flex;
}
.chart-container > canvas {
  width: 100% !important;
  height: 100% !important;
}
.card-full { width: 100%; display: flex; flex-direction: column; }
.card-full :deep(.p-card-body) { display: flex; flex-direction: column; height: 100%; }
.card-full :deep(.p-card-content) { flex: 1; display: flex; flex-direction: column; }
.empty-offset { flex: 1; min-height: 400px; position: relative; }
.empty-offset > span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
}
</style>

