<template>
  <div class="chart-wrap">
    <v-chart :option="option" autoresize class="h-96 w-full" />
  </div>
</template>

<script>
import { defineComponent } from 'vue'
import VChart from 'vue-echarts'
import * as echarts from 'echarts/core'
import { LineChart, ScatterChart } from 'echarts/charts'
import { GridComponent, LegendComponent, TooltipComponent, DataZoomComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'

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 { getStrategyColor } from '../lib/chartColors'

echarts.use([LineChart, GridComponent, ScatterChart, LegendComponent, TooltipComponent, DataZoomComponent, CanvasRenderer])

const ASSET_CUTOFF = {
  BTC: '2025-08-01',
  // ETH: '2025-08-15',
};

// Stable palette per agent (tweak as you like)
const AGENT_PALETTE = [
  '#6D4CFE', // indigo
  '#FF6B6B', // coral
  '#10B981', // emerald
  '#F59E0B', // amber
  '#06B6D4', // cyan
  '#A855F7', // violet
  '#64748B', // slate
  '#E11D48', // rose
  '#0EA5E9', // sky
  '#84CC16', // lime
]

// pick color by agent name + index (from agentColorIndex map)
function getAgentColor(agent, idx = 0) {
  // keep simple + deterministic
  return AGENT_PALETTE[idx % AGENT_PALETTE.length]
}

function drawImageInCircle(ctx, img, cx, cy, radius, { mode = 'contain', padding = 0 } = {}) {
  if (!img) return;
  const r = Math.max(0, radius - padding);
  ctx.save();
  ctx.beginPath();
  ctx.arc(cx, cy, r, 0, Math.PI * 2);
  ctx.clip();

  const iw = img.naturalWidth || img.width;
  const ih = img.naturalHeight || img.height;
  if (!iw || !ih) { ctx.restore(); return; }

  // target box (square) that we want to fill with the image
  const tw = r * 2;
  const th = r * 2;

  // scale (cover vs contain)
  const scale = (mode === 'contain')
    ? Math.min(tw / iw, th / ih)
    : Math.max(tw / iw, th / ih); // cover (default)

  const dw = iw * scale;
  const dh = ih * scale;

  // center align
  const dx = cx - dw / 2;
  const dy = cy - dh / 2;

  ctx.imageSmoothingEnabled = true;
  ctx.imageSmoothingQuality = 'high';
  ctx.drawImage(img, dx, dy, dw, dh);
  ctx.restore();
}


// helper: convert [ [date, y], ... ] into % since first y
function toPct(points){
  if (!Array.isArray(points) || !points.length) return points
  const y0 = points[0][1]
  if (typeof y0 !== 'number' || !isFinite(y0) || y0 === 0) return points
  return points.map(([t, y]) => [t, ((y / y0) - 1) * 100])
}

// --- Agent & Model logo registries (fill with your actual assets)
const AGENT_LOGOS = {
  'HedgeFundAgent': new URL('../assets/images/agents_images/hedgefund.png', import.meta.url).href,
  'DeepFundAgent': new URL('../assets/images/agents_images/deepfund.png', import.meta.url).href,
  'TradeAgent': new URL('../assets/images/agents_images/trade.png', import.meta.url).href,
  'InvestorAgent': new URL('../assets/images/agents_images/investor.png', import.meta.url).href,
  'BTC': new URL('../assets/images/assets_images/BTC.png', import.meta.url).href,
  'ETH': new URL('../assets/images/assets_images/ETH.png', import.meta.url).href,
  'MSFT': new URL('../assets/images/assets_images/MSFT.png', import.meta.url).href,
  'BMRN': new URL('../assets/images/assets_images/BMRN.png', import.meta.url).href,
  'MRNA': new URL('../assets/images/assets_images/MRNA.png', import.meta.url).href,
  'TSLA': new URL('../assets/images/assets_images/TSLA.png', import.meta.url).href,
  // 'InvestorAgent': new URL('../assets/images/agents_images/investor.png', import.meta.url).href,
};
const MODEL_LOGOS = {
  'claude_3_5_haiku_20241022': new URL('../assets/images/models_images/claude.png', import.meta.url).href,
  'claude_sonnet_4_2025051': new URL('../assets/images/models_images/claude.png', import.meta.url).href,
  'gpt_4o': new URL('../assets/images/models_images/gpt.png', import.meta.url).href,
  'gpt_4.1': new URL('../assets/images/models_images/gpt.png', import.meta.url).href,
  'gemini_2.0_flash': new URL('../assets/images/models_images/gemini.png', import.meta.url).href,
};

// Canvas badge cache: key = `${agent}|${model}|${color}`
const BADGE_CACHE = new Map();

const loadImg = (url) => new Promise((resolve, reject) => {
  if (!url) return resolve(null);
  const img = new Image();
  img.crossOrigin = 'anonymous';
  img.onload = () => resolve(img);
  img.onerror = () => resolve(null); // fail soft
  img.src = url;
});

// Compose a badge: [ colored circle with agent logo ] + [ white rounded square with model logo ]
async function composeBadge(agent, model, color = '#666') {
  const key = `circ|${agent}|${model ?? ''}|${color}`;
  if (BADGE_CACHE.has(key)) return BADGE_CACHE.get(key);

  const aImg = await loadImg(AGENT_LOGOS[agent]);
  const mImg = await loadImg(MODEL_LOGOS[model]);

  // uniform canvas
  const S = 30;                   // badge size (px)
  const R = S / 2;
  const canvas = document.createElement('canvas');
  canvas.width = S; canvas.height = S;
  const ctx = canvas.getContext('2d');

  const ring = 3;           // outer colored ring thickness
  const padImg = 4;         // extra breathing room for the logo

  // base colored circle (ring)
  ctx.fillStyle = color;
  ctx.beginPath(); ctx.arc(R, R, R, 0, Math.PI * 2); ctx.fill();

  // inner white disk
  ctx.fillStyle = '#fff';
  ctx.beginPath(); ctx.arc(R, R, R - ring, 0, Math.PI * 2); ctx.fill();

  // agent logo (fit into inner circle)
  if (aImg) {
    drawImageInCircle(ctx, aImg, R, R, R - ring, { mode: 'contain', padding: padImg });
  }

  // model puck (bottom-right)
  if (mImg) {
    const d = 20, r = d / 2;                  // puck diameter
    const cx = S - r + 1, cy = S - r + 1;     // slight outside bias
    // white border
    ctx.fillStyle = '#fff';
    ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI * 2); ctx.fill();
    // inner image circle
    ctx.save();
    ctx.beginPath(); ctx.arc(cx, cy, r - 1.5, 0, Math.PI * 2); ctx.clip();
    const imgInset = 3;
    ctx.drawImage(mImg, cx - r + imgInset, cy - r + imgInset, d - imgInset * 2, d - imgInset * 2);
    ctx.restore();
  }

  const url = canvas.toDataURL('image/png');
  BADGE_CACHE.set(key, url);
  return url;
}

let markerToLine = new Map()

export default defineComponent({
  name: 'CompareChartE',
  components: { VChart },
  props: {
    selected: { type: Array, default: () => [] },
    visible: { type: Boolean, default: true },
    // NEW: $/% toggle
    mode: { type: String, default: 'usd' } // 'usd' | 'pct'
  },
  data(){ return { option: {} } },
  watch: {
    selected: { deep: true, handler(){ this.rebuild() } },
    visible(v){ if (v) this.$nextTick(() => this.rebuild()) },
    // NEW: rebuild when the toggle changes
    mode(){ this.rebuild() }
  },
  mounted(){ this.$nextTick(() => this.rebuild()) },
  methods: {
    async getAll(){
      let all = getAllDecisions() || []
      if (!all.length) {
        try { const cached = await readAllRawDecisions(); if (cached?.length) all = cached } catch {}
      }
      return all
    },
    async rebuild(){
      if (!this.visible) return
      const selected = Array.isArray(this.selected) ? this.selected : []
      const all = await this.getAll()
      const groupKeyToSeq = new Map()

      // 1) Build sequences exactly like CompareChart.vue
      for (const sel of selected) {
        const { agent_name: agent, asset, model } = sel
        const ids = Array.isArray(sel.decision_ids) ? sel.decision_ids : []
        let seq = ids.length ? all.filter(r => ids.includes(r.id))
                             : 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'
        let filtered = isCrypto ? seq : await filterRowsToNyseTradingDays(seq)

        // --- asset-specific cutoff ---
        const cutoff = ASSET_CUTOFF[asset]
        if (cutoff) {
          const t0 = new Date(cutoff + 'T00:00:00Z')
          filtered = filtered.filter(r => new Date(r.date + 'T00:00:00Z') >= t0)
        }
        groupKeyToSeq.set(`${agent}|${asset}|${model}`, { sel, seq: filtered })
      }

      // 2) Build series using (time,value) pairs
      const series = []
      const legend = []
      const assets = new Set()
      const agentColorIndex = new Map()

      for (const [_, { sel, seq }] of groupKeyToSeq.entries()) {
        if (!seq.length) continue
        const agent = sel.agent_name
        const asset = sel.asset
        assets.add(asset)

        const idx = agentColorIndex.get(agent) ?? agentColorIndex.size
        agentColorIndex.set(agent, idx)

        const cfg = (STRATEGIES || []).find(s => s.id === sel.strategy) || { strategy: 'long_only', tradingMode: 'aggressive', fee: 0.0005, label: 'Selected' }
        const stratY = computeStrategyEquity(seq, 100000, cfg.fee, cfg.strategy, cfg.tradingMode) || []
        let points = seq.map((row, i) => [row.date, stratY[i]])

        // NEW: convert to % mode if requested
        if (this.mode === 'pct') points = toPct(points)

        const name = `${agent} · ${sel.model} · ${cfg.label}`
        legend.push(name)
        series.push({
          name,
          type: 'line',
          showSymbol: false,
          smooth: false,
          emphasis: {
            focus: 'series',
            lineStyle: { width: 3.5 },
          },
          lineStyle: { width: 2, color: getAgentColor(agent, idx) },
          data: points
        })
        const lineSeriesIndex = series.length - 1;
        const last = points?.[points.length - 1];
        if (last && Number.isFinite(last[1])) {
          const lineColor = getAgentColor(agent, idx);
          const badgeUrl = await composeBadge(agent, null, lineColor);  // ← NEW
          series.push({
            name: name + ' •badge',
            type: 'scatter',
            data: [ last ],
            symbol: badgeUrl ? `image://${badgeUrl}` : 'circle',
            symbolSize: 30,
            z: 20,
            tooltip: {
              trigger: 'item',
              appendToBody: true,
              formatter: (p) => {
                const v = p.value?.[1]
                const val = this.mode === 'pct'
                  ? `${v >= 0 ? '+' : ''}${Number(v).toFixed(2)}%`
                  : Number(v ?? 0).toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
                return [
                  `<div style="font-weight:600">${sel.agent_name}</div>`,
                  sel.model ? `<div style="opacity:.8">${sel.model}</div>` : '',
                  `<div style="opacity:.8">${sel.asset}</div>`,
                  `<div style="margin-top:4px">${val}</div>`
                ].join('')
              }
            },
            label: {
              show: true,
              position: 'right',
              padding: [4,8],
              borderRadius: 10,
              backgroundColor: lineColor,
              color: '#fff',
              fontWeight: 700,
              formatter: (p) => {
                const v = p.value?.[1];
                if (this.mode === 'pct') return (v >= 0 ? '+' : '') + (Number(v).toFixed(2)) + '%';
                return Number(v ?? 0).toLocaleString(undefined, { style:'currency', currency:'USD', maximumFractionDigits: 2 });
              }
            },
            itemStyle: { color: lineColor }
          });
        }
      }

      // 3) Buy & Hold baseline per asset
      for (const asset of assets) {
        const entry = [...groupKeyToSeq.values()].find(v => v.sel.asset === asset)
        if (!entry) continue
        const bhY = computeBuyHoldEquity(entry.seq, 100000) || []
        let bhPoints = entry.seq.map((row, i) => [row.date, bhY[i]])

        // NEW: % mode for baseline too
        if (this.mode === 'pct') bhPoints = toPct(bhPoints)

        series.push({
          name: `${asset} · Buy&Hold`,
          type: 'line',
          showSymbol: false,
          lineStyle: { width: 1.5, type: 'dashed' },
          color: getStrategyColor('', true, 0),
          data: bhPoints
        })
        const lastBH = bhPoints[bhPoints.length - 1]
        if (lastBH && Number.isFinite(lastBH[1])) {
          const baseColor = getStrategyColor('', true, 0);
          const badgeUrl = await composeBadge(asset, null, baseColor);  // ← NEW
          series.push({
            name: `${asset} · Buy&Hold •badge`,
            type: 'scatter',
            data: [ lastBH ],
            symbol: badgeUrl ? `image://${badgeUrl}` : 'circle',
            symbolSize: 30,
            z: 19,
            tooltip: { show: false },
            label: {
              show: true,
              position: 'right',
              padding: [4,8],
              borderRadius: 10,
              backgroundColor: baseColor,
              color: '#fff',
              fontWeight: 700,
              formatter: (p) => {
                const v = p.value?.[1];
                if (this.mode === 'pct') return (v >= 0 ? '+' : '') + (Number(v).toFixed(2)) + '%';
                return Number(v ?? 0).toLocaleString(undefined, { style:'currency', currency:'USD', maximumFractionDigits: 2 });
              }
            },
            itemStyle: { color: baseColor }
          });
        }
        legend.push(`${asset} · Buy&Hold`)
      }

      this.option = {
        animation: true,
        grid: { left: 64, right: 200, top: 8, bottom: 52 },
        tooltip: {
          trigger: 'axis',
          axisPointer: { type: 'line' },
          // NEW: format per mode
          valueFormatter: v => {
            if (typeof v !== 'number') return v
            return this.mode === 'pct'
              ? `${v.toFixed(2)}%`
              : v.toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
          }
        },
        legend: { show: false },
        xAxis: { type: 'time' },
        yAxis: this.mode === 'pct'
          ? {
              type: 'value', scale: true,
              axisLabel: { formatter: v => `${Number(v).toLocaleString(undefined, { maximumFractionDigits: 0 })}%` }
            }
          : {
              type: 'value', scale: true,
              axisLabel: { formatter: v => Number(v).toLocaleString(undefined, {style:'currency', currency:'USD', maximumFractionDigits:0 }) }
            },
        dataZoom: [{ type: 'inside', throttle: 50 }, { type: 'slider', height: 14, bottom: 36 }],
        series
      }
    }
  }
})
</script>

<style scoped>
.chart-wrap { width: 100%; }
.h-96 { height: 24rem; }
</style>
