'use client';

import { useState, useEffect, useMemo, useRef } from 'react';
import { fetchFundHistory } from '../api/fund';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronIcon } from './Icons';
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  Title,
  Tooltip,
  Legend,
  Filler
} from 'chart.js';
import { Line } from 'react-chartjs-2';
import {cachedRequest} from "../lib/cacheRequest";

ChartJS.register(
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  Title,
  Tooltip,
  Legend,
  Filler
);

const CHART_COLORS = {
  dark: {
    danger: '#f87171',
    success: '#34d399',
    primary: '#22d3ee',
    muted: '#9ca3af',
    border: '#1f2937',
    text: '#e5e7eb',
    crosshairText: '#0f172a',
  },
  light: {
    danger: '#dc2626',
    success: '#059669',
    primary: '#0891b2',
    muted: '#475569',
    border: '#e2e8f0',
    text: '#0f172a',
    crosshairText: '#ffffff',
  }
};

function getChartThemeColors(theme) {
  return CHART_COLORS[theme] || CHART_COLORS.dark;
}

export default function FundTrendChart({ code, isExpanded, onToggleExpand, transactions = [], theme = 'dark', hideHeader = false }) {
  const [range, setRange] = useState('1m');
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const chartRef = useRef(null);
  const hoverTimeoutRef = useRef(null);

  const chartColors = useMemo(() => getChartThemeColors(theme), [theme]);

  useEffect(() => {
    // If collapsed, don't fetch data unless we have no data yet
    if (!isExpanded && data.length > 0) return;

    let active = true;
    setLoading(true);
    setError(null);
    const cacheKey = `fund_history_${code}_${range}`;

    if (isExpanded) {
      cachedRequest(
        () => fetchFundHistory(code, range),
        cacheKey,
        { cacheTime: 10 * 60 * 1000 }
      )
        .then(res => {
          if (active) {
            setData(res || []);
            setLoading(false);
          }
        })
        .catch(err => {
          if (active) {
            setError(err);
            setLoading(false);
          }
        });

    }
    return () => { active = false; };
  }, [code, range, isExpanded, data.length]);

  const ranges = [
    { label: '近1月', value: '1m' },
    { label: '近3月', value: '3m' },
    { label: '近6月', value: '6m' },
    { label: '近1年', value: '1y' },
    { label: '近3年', value: '3y' },
    { label: '成立来', value: 'all' }
  ];

  const change = useMemo(() => {
     if (!data.length) return 0;
     const first = data[0].value;
     const last = data[data.length - 1].value;
     return ((last - first) / first) * 100;
  }, [data]);

  // Red for up, Green for down (CN market style)，随主题使用 CSS 变量
  const upColor = chartColors.danger;
  const downColor = chartColors.success;
  const lineColor = change >= 0 ? upColor : downColor;
  const primaryColor = chartColors.primary;

  const chartData = useMemo(() => {
    // Calculate percentage change based on the first data point
    const firstValue = data.length > 0 ? data[0].value : 1;
    const percentageData = data.map(d => ((d.value - firstValue) / firstValue) * 100);

    // Map transaction dates to chart indices
    const dateToIndex = new Map(data.map((d, i) => [d.date, i]));
    const buyPoints = new Array(data.length).fill(null);
    const sellPoints = new Array(data.length).fill(null);

    transactions.forEach(t => {
        // Simple date matching (assuming formats match)
        // If formats differ, dayjs might be needed
        const idx = dateToIndex.get(t.date);
        if (idx !== undefined) {
            const val = percentageData[idx];
            if (t.type === 'buy') {
                buyPoints[idx] = val;
            } else {
                sellPoints[idx] = val;
            }
        }
    });

    return {
      labels: data.map(d => d.date),
      datasets: [
        {
          type: 'line',
          label: '涨跌幅',
          data: percentageData,
          borderColor: lineColor,
          backgroundColor: (context) => {
            const ctx = context.chart.ctx;
            const gradient = ctx.createLinearGradient(0, 0, 0, 200);
            gradient.addColorStop(0, `${lineColor}33`); // 20% opacity
            gradient.addColorStop(1, `${lineColor}00`); // 0% opacity
            return gradient;
          },
          borderWidth: 2,
          pointRadius: 0,
          pointHoverRadius: 4,
          fill: true,
          tension: 0.2,
          order: 2
        },
        {
          type: 'line', // Use line type with showLine: false to simulate scatter on Category scale
          label: '买入',
          data: buyPoints,
          borderColor: '#ffffff',
          borderWidth: 1,
          backgroundColor: primaryColor,
          pointStyle: 'circle',
          pointRadius: 2.5,
          pointHoverRadius: 4,
          showLine: false,
          order: 1
        },
        {
          type: 'line',
          label: '卖出',
          data: sellPoints,
          borderColor: '#ffffff',
          borderWidth: 1,
          backgroundColor: upColor,
          pointStyle: 'circle',
          pointRadius: 2.5,
          pointHoverRadius: 4,
          showLine: false,
          order: 1
        }
      ]
    };
  }, [data, transactions, lineColor, primaryColor, upColor]);

  const options = useMemo(() => {
    const colors = getChartThemeColors(theme);
    return {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: {
          display: false
        },
        tooltip: {
          enabled: false, // 禁用默认 Tooltip，使用自定义绘制
          mode: 'index',
          intersect: false,
          external: () => {} // 禁用外部 HTML tooltip
        }
      },
      scales: {
        x: {
          display: true,
          grid: {
            display: false,
            drawBorder: false
          },
          ticks: {
            color: colors.muted,
            font: { size: 10 },
            maxTicksLimit: 4,
            maxRotation: 0
          },
          border: { display: false }
        },
        y: {
          display: true,
          position: 'left',
          grid: {
            color: colors.border,
            drawBorder: false,
            tickLength: 0
          },
          ticks: {
            color: colors.muted,
            font: { size: 10 },
            count: 5,
            callback: (value) => `${value.toFixed(2)}%`
          },
          border: { display: false }
        }
      },
      interaction: {
        mode: 'index',
        intersect: false,
      },
      onHover: (event, chartElement, chart) => {
        const target = event?.native?.target;
        const currentChart = chart || chartRef.current;
        if (!currentChart) return;

        const tooltipActive = currentChart.tooltip?._active ?? [];
        const activeElements = currentChart.getActiveElements
          ? currentChart.getActiveElements()
          : [];
        const hasActive =
          (chartElement && chartElement.length > 0) ||
          (tooltipActive && tooltipActive.length > 0) ||
          (activeElements && activeElements.length > 0);

        if (target) {
          target.style.cursor = hasActive ? 'crosshair' : 'default';
        }

        // 仅用于桌面端 hover 改变光标，不在这里做 2 秒清除，避免移动端 hover 事件不稳定
      },
      onClick: () => {}
    };
  }, [theme]);

  useEffect(() => {
    return () => {
      if (hoverTimeoutRef.current) {
        clearTimeout(hoverTimeoutRef.current);
      }
    };
  }, []);

  const plugins = useMemo(() => {
    const colors = getChartThemeColors(theme);
    return [{
    id: 'crosshair',
    afterEvent: (chart, args) => {
      const { event, replay } = args || {};
      if (!event || replay) return; // 忽略动画重放
    
      const type = event.type;
      if (type === 'mousemove' || type === 'click') {
        if (hoverTimeoutRef.current) {
          clearTimeout(hoverTimeoutRef.current);
          hoverTimeoutRef.current = null;
        }
    
        hoverTimeoutRef.current = setTimeout(() => {
          if (!chart) return;
          chart.setActiveElements([]);
          if (chart.tooltip) {
            chart.tooltip.setActiveElements([], { x: 0, y: 0 });
          }
          chart.update();
        }, 2000);
      }
    },
    afterDraw: (chart) => {
      const ctx = chart.ctx;
      const datasets = chart.data.datasets;
      const primaryColor = colors.primary;

      // 绘制圆角矩形（兼容无 roundRect 的环境）
      const drawRoundRect = (left, top, w, h, r) => {
        const rad = Math.min(r, w / 2, h / 2);
        ctx.beginPath();
        ctx.moveTo(left + rad, top);
        ctx.lineTo(left + w - rad, top);
        ctx.quadraticCurveTo(left + w, top, left + w, top + rad);
        ctx.lineTo(left + w, top + h - rad);
        ctx.quadraticCurveTo(left + w, top + h, left + w - rad, top + h);
        ctx.lineTo(left + rad, top + h);
        ctx.quadraticCurveTo(left, top + h, left, top + h - rad);
        ctx.lineTo(left, top + rad);
        ctx.quadraticCurveTo(left, top, left + rad, top);
        ctx.closePath();
      };

      const drawPointLabel = (datasetIndex, index, text, bgColor, textColor = '#ffffff', yOffset = 0) => {
          const meta = chart.getDatasetMeta(datasetIndex);
          if (!meta.data[index]) return;
          const element = meta.data[index];
          if (element.skip) return;

          const x = element.x;
          const y = element.y + yOffset;
          const paddingH = 10;
          const paddingV = 6;
          const radius = 8;

          ctx.save();
          ctx.font = 'bold 11px sans-serif';
          const textW = ctx.measureText(text).width;
          const w = textW + paddingH * 2;
          const h = 18;

          // 计算原始 left，并对左右边界做收缩，避免在最右/最左侧被裁剪
          const chartLeft = chart.scales.x.left;
          const chartRight = chart.scales.x.right;
          let left = x - w / 2;
          if (left < chartLeft) left = chartLeft;
          if (left + w > chartRight) left = chartRight - w;
          const centerX = left + w / 2;

          const top = y - 24;

          drawRoundRect(left, top, w, h, radius);
          ctx.globalAlpha = 0.7;
          ctx.fillStyle = bgColor;
          ctx.fill();

          ctx.globalAlpha = 0.7;
          ctx.fillStyle = textColor;
          ctx.textAlign = 'center';
          ctx.textBaseline = 'middle';
          ctx.fillText(text, centerX, top + h / 2);
          ctx.restore();
      };

      // Resolve active elements (hover/focus) first — used to decide whether to show default labels
      let activeElements = [];
      if (chart.tooltip?._active?.length) {
        activeElements = chart.tooltip._active;
      } else {
        activeElements = chart.getActiveElements();
      }

      // 1. Draw default labels for first buy and sell points only when NOT focused/hovering
      // Index 1 is Buy, Index 2 is Sell
      if (!activeElements?.length && datasets[1] && datasets[1].data) {
          const firstBuyIndex = datasets[1].data.findIndex(v => v !== null && v !== undefined);
          if (firstBuyIndex !== -1) {
              let sellIndex = -1;
              if (datasets[2] && datasets[2].data) {
                  sellIndex = datasets[2].data.findIndex(v => v !== null && v !== undefined);
              }
              const isCollision = (firstBuyIndex === sellIndex);
              drawPointLabel(1, firstBuyIndex, '买入', primaryColor, '#ffffff', isCollision ? -20 : 0);
          }
      }
      if (!activeElements?.length && datasets[2] && datasets[2].data) {
          const firstSellIndex = datasets[2].data.findIndex(v => v !== null && v !== undefined);
          if (firstSellIndex !== -1) {
              drawPointLabel(2, firstSellIndex, '卖出', '#f87171');
          }
      }

      // 2. Handle active elements (hover crosshair)
      if (activeElements && activeElements.length) {
        const activePoint = activeElements[0];
        const x = activePoint.element.x;
        const y = activePoint.element.y;
        const topY = chart.scales.y.top;
        const bottomY = chart.scales.y.bottom;
        const leftX = chart.scales.x.left;
        const rightX = chart.scales.x.right;

        ctx.save();
        ctx.beginPath();
        ctx.setLineDash([3, 3]);
        ctx.lineWidth = 1;
        ctx.strokeStyle = colors.muted;

        // Draw vertical line
        ctx.moveTo(x, topY);
        ctx.lineTo(x, bottomY);

        // Draw horizontal line (based on first point - usually the main line)
        ctx.moveTo(leftX, y);
        ctx.lineTo(rightX, y);

        ctx.stroke();

        // Draw labels
        ctx.font = '10px sans-serif';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // Draw Axis Labels based on the first point (main line)
        const datasetIndex = activePoint.datasetIndex;
        const index = activePoint.index;

        const labels = chart.data.labels;

        if (labels && datasets && datasets[datasetIndex] && datasets[datasetIndex].data) {
           const dateStr = labels[index];
           const value = datasets[datasetIndex].data[index];

           if (dateStr !== undefined && value !== undefined) {
              // X axis label (date) with boundary clamping
               const textWidth = ctx.measureText(dateStr).width + 8;
               const chartLeft = chart.scales.x.left;
               const chartRight = chart.scales.x.right;
               let labelLeft = x - textWidth / 2;
               if (labelLeft < chartLeft) labelLeft = chartLeft;
               if (labelLeft + textWidth > chartRight) labelLeft = chartRight - textWidth;
               const labelCenterX = labelLeft + textWidth / 2;
               ctx.fillStyle = primaryColor;
               ctx.fillRect(labelLeft, bottomY, textWidth, 16);
               ctx.fillStyle = colors.crosshairText;
               ctx.fillText(dateStr, labelCenterX, bottomY + 8);

               // Y axis label (value)
               const valueStr = (typeof value === 'number' ? value.toFixed(2) : value) + '%';
               const valWidth = ctx.measureText(valueStr).width + 8;
               ctx.fillStyle = primaryColor;
               ctx.fillRect(leftX, y - 8, valWidth, 16);
               ctx.fillStyle = colors.crosshairText;
               ctx.textAlign = 'center';
               ctx.fillText(valueStr, leftX + valWidth / 2, y);
           }
        }

        // Check for collision between Buy (1) and Sell (2) in active elements
        const activeBuy = activeElements.find(e => e.datasetIndex === 1);
        const activeSell = activeElements.find(e => e.datasetIndex === 2);
        const isCollision = activeBuy && activeSell && activeBuy.index === activeSell.index;

        // Iterate through all active points to find transaction points and draw their labels
        activeElements.forEach(element => {
            const dsIndex = element.datasetIndex;
            // Only for transaction datasets (index > 0)
            if (dsIndex > 0 && datasets[dsIndex]) {
                const label = datasets[dsIndex].label;
                // Determine background color based on dataset index
                // 1 = Buy (主题色), 2 = Sell (与折线图红色一致)
                const bgColor = dsIndex === 1 ? primaryColor : colors.danger;

                // If collision, offset Buy label upwards
                let yOffset = 0;
                if (isCollision && dsIndex === 1) {
                    yOffset = -20;
                }

                drawPointLabel(dsIndex, element.index, label, bgColor, '#ffffff', yOffset);
            }
        });

        ctx.restore();
      }
    }
  }];
  }, [theme]); // theme 变化时重算以应用亮色/暗色坐标轴与 crosshair

  const chartBlock = (
    <>
      <div style={{ position: 'relative', height: 180, width: '100%', touchAction: 'pan-y' }}>
        {loading && (
          <div className="chart-overlay" style={{ backdropFilter: 'blur(2px)' }}>
            <span className="muted" style={{ fontSize: '12px' }}>加载中...</span>
          </div>
        )}

        {!loading && data.length === 0 && (
          <div className="chart-overlay">
            <span className="muted" style={{ fontSize: '12px' }}>暂无数据</span>
          </div>
        )}

        {data.length > 0 && (
          <Line ref={chartRef} data={chartData} options={options} plugins={plugins} />
        )}
      </div>

      <div className="trend-range-bar">
        {ranges.map(r => (
          <button
            key={r.value}
            type="button"
            className={`trend-range-btn ${range === r.value ? 'active' : ''}`}
            onClick={(e) => { e.stopPropagation(); setRange(r.value); }}
          >
            {r.label}
          </button>
        ))}
      </div>
    </>
  );

  return (
    <div style={{ marginTop: hideHeader ? 0 : 16 }} onClick={(e) => e.stopPropagation()}>
      {!hideHeader && (
        <div
          style={{ marginBottom: 8, cursor: 'pointer', userSelect: 'none' }}
          className="title"
          onClick={onToggleExpand}
        >
          <div className="row" style={{ width: '100%', flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span>业绩走势</span>
              <ChevronIcon
                width="16"
                height="16"
                className="muted"
                style={{
                  transform: !isExpanded ? 'rotate(-90deg)' : 'rotate(0deg)',
                  transition: 'transform 0.2s ease'
                }}
              />
            </div>
            {data.length > 0 && (
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span className="muted">{ranges.find(r => r.value === range)?.label}涨跌幅</span>
                <span style={{ color: lineColor, fontWeight: 600 }}>
                  {change > 0 ? '+' : ''}{change.toFixed(2)}%
                </span>
              </div>
            )}
          </div>
        </div>
      )}

      {hideHeader && data.length > 0 && (
        <div className="row" style={{ marginBottom: 8, justifyContent: 'flex-end' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <span className="muted">{ranges.find(r => r.value === range)?.label}涨跌幅</span>
            <span style={{ color: lineColor, fontWeight: 600 }}>
              {change > 0 ? '+' : ''}{change.toFixed(2)}%
            </span>
          </div>
        </div>
      )}

      {hideHeader ? (
        chartBlock
      ) : (
        <AnimatePresence>
          {isExpanded && (
            <motion.div
              initial={{ height: 0, opacity: 0 }}
              animate={{ height: 'auto', opacity: 1 }}
              exit={{ height: 0, opacity: 0 }}
              transition={{ duration: 0.3, ease: 'easeInOut' }}
              style={{ overflow: 'hidden' }}
            >
              {chartBlock}
            </motion.div>
          )}
        </AnimatePresence>
      )}
    </div>
  );
}
