"use client";

import { useEffect, useRef, useState } from "react";

// ═══════════ Colors ═══════════
const BLUE = "#1E5AA8";
const BLUE_FILL = "rgba(30,90,168,0.15)";
const GRAY = "#888888";
const BLACK = "#111111";
const GRID = "rgba(0,0,0,0.06)";
const BG = "#FFFFFF";

interface QuantData {
  meta: { strategyName: string; strategyId: string; generatedAt: string };
  equityCurve: { date: string; value: number }[];
  monthlyReturns: { years: number[]; months: string[]; matrix: (number | null)[][] };
  yearlyReturns: { year: number; return: number }[];
  meanYearlyReturn: number;
  monthlyReturnDistribution: { bins: { start: number; end: number; count: number }[]; mean: number };
  qqPlot: { points: { theoretical: number; observed: number }[] };
  rollingStats: { windowMonths: number; series: { date: string; rollingReturn: number; rollingVolatility: number }[] };
}

interface Props {
  strategyName: string;
  backtestId: string;
  className?: string;
}

export default function QuantReport({ strategyName, backtestId, className = "" }: Props) {
  const [data, setData] = useState<QuantData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  // Canvas refs
  const equityCanvas = useRef<HTMLCanvasElement>(null);
  const monthlyCanvas = useRef<HTMLCanvasElement>(null);
  const yearlyCanvas = useRef<HTMLCanvasElement>(null);
  const distCanvas = useRef<HTMLCanvasElement>(null);
  const qqCanvas = useRef<HTMLCanvasElement>(null);
  const rollingCanvas = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    setLoading(true);
    fetch(`/cv/api/quant-report/${backtestId}`)
      .then(r => r.json())
      .then(d => { setData(d); setLoading(false); })
      .catch(e => { setError(e.message); setLoading(false); });
  }, [backtestId]);

  // ═══════ Equity Curve ═══════
  useEffect(() => {
    if (!data?.equityCurve?.length) return;
    const canvas = equityCanvas.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d")!;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.clientWidth;
    const H = canvas.clientHeight;
    canvas.width = W * dpr; canvas.height = H * dpr;
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    ctx.fillStyle = BG; ctx.fillRect(0, 0, W, H);

    const curve = data.equityCurve;
    const M = { top: 30, bot: 35, left: 45, right: 15 };
    const pW = W - M.left - M.right, pH = H - M.top - M.bot;
    const vals = curve.map(c => c.value);
    const minV = Math.min(...vals) * 0.95;
    const maxV = Math.max(...vals) * 1.05;
    const range = maxV - minV || 1;

    const toX = (i: number) => M.left + (i / (curve.length - 1)) * pW;
    const toY = (v: number) => M.top + pH - ((v - minV) / range) * pH;

    // Title
    ctx.fillStyle = BLACK; ctx.font = "bold 13px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText("Strategy Performance", 8, 18);

    // Legend
    ctx.fillStyle = BLUE; ctx.font = "11px sans-serif";
    ctx.fillText(data.meta.strategyName, 8, M.top + pH + 18);

    // Grid
    ctx.strokeStyle = GRID; ctx.lineWidth = 0.5;
    for (let i = 0; i <= 5; i++) {
      const y = M.top + (i / 5) * pH;
      ctx.beginPath(); ctx.moveTo(M.left, y); ctx.lineTo(M.left + pW, y); ctx.stroke();
    }

    // Line
    ctx.strokeStyle = BLUE; ctx.lineWidth = 1.5;
    ctx.beginPath();
    for (let i = 0; i < curve.length; i++) {
      const x = toX(i), y = toY(curve[i].value);
      i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    }
    ctx.stroke();

    // Y axis labels
    ctx.fillStyle = GRAY; ctx.font = "9px sans-serif";
    ctx.textAlign = "right";
    for (let i = 0; i <= 4; i++) {
      const v = minV + (i / 4) * range;
      ctx.fillText(v.toFixed(1), M.left - 4, toY(v) + 3);
    }

    // X axis: years
    ctx.textAlign = "center";
    const years = [...new Set(curve.map(c => c.date.slice(0, 4)))];
    for (const yr of years.slice(0, 6)) {
      const pts = curve.filter(c => c.date.startsWith(yr));
      if (pts.length) {
        const idx = curve.indexOf(pts[Math.floor(pts.length / 2)]);
        ctx.fillText(yr, toX(idx), M.top + pH + 14);
      }
    }
  }, [data]);

  // ═══════ Monthly Returns Heatmap ═══════
  useEffect(() => {
    if (!data?.monthlyReturns?.matrix?.length) return;
    const canvas = monthlyCanvas.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d")!;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.clientWidth, H = 340;
    canvas.width = W * dpr; canvas.height = H * dpr;
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    ctx.fillStyle = BG; ctx.fillRect(0, 0, W, H);

    const mr = data.monthlyReturns;
    const M = { top: 25, bot: 5, left: 35, right: 5 };
    const nRows = mr.years.length, nCols = 12;
    const cellW = (W - M.left - M.right) / nCols;
    const cellH = (H - M.top - M.bot) / nRows;

    ctx.fillStyle = BLACK; ctx.font = "bold 12px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText("Monthly Returns", 8, 16);

    // Month headers
    ctx.font = "9px sans-serif";
    ctx.textAlign = "center";
    for (let c = 0; c < 12; c++) {
      ctx.fillText(mr.months[c].slice(0, 3), M.left + c * cellW + cellW / 2, M.top - 5);
    }

    // Heatmap cells
    const allVals = mr.matrix.flat().filter(v => v !== null) as number[];
    const maxAbs = Math.max(Math.abs(Math.max(...allVals)), Math.abs(Math.min(...allVals)), 1);

    for (let r = 0; r < nRows; r++) {
      // Year label
      ctx.fillStyle = BLACK; ctx.font = "10px sans-serif";
      ctx.textAlign = "right";
      ctx.fillText(String(mr.years[r]), M.left - 4, M.top + r * cellH + cellH * 0.65);

      for (let c = 0; c < nCols; c++) {
        const v = mr.matrix[r][c];
        const x = M.left + c * cellW, y = M.top + r * cellH;
        if (v !== null && v !== undefined) {
          // Color: blue saturation proportional to value
          const alpha = Math.min(1, Math.abs(v) / maxAbs * 0.9 + 0.1);
          ctx.fillStyle = `rgba(30,90,168,${alpha})`;
          ctx.fillRect(x, y, cellW - 1, cellH - 1);
          // Value text
          ctx.fillStyle = Math.abs(v) > maxAbs * 0.4 ? "#FFFFFF" : "#111111";
          ctx.font = "9px sans-serif";
          ctx.textAlign = "center";
          ctx.fillText(v.toFixed(1), x + cellW / 2, y + cellH * 0.65);
        }
      }
    }
  }, [data]);

  // ═══════ Yearly Returns Bar Chart ═══════
  useEffect(() => {
    if (!data?.yearlyReturns?.length) return;
    const canvas = yearlyCanvas.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d")!;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.clientWidth, H = 340;
    canvas.width = W * dpr; canvas.height = H * dpr;
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    ctx.fillStyle = BG; ctx.fillRect(0, 0, W, H);

    const yr = data.yearlyReturns;
    const M = { top: 25, bot: 5, left: 8, right: 40 };
    const pH = (H - M.top - M.bot) / yr.length;
    const minR = Math.min(0, ...yr.map(y => y.return));
    const maxR = Math.max(...yr.map(y => y.return));
    const range = Math.max(maxR - minR, 1);
    const zeroX = M.left + ((-minR) / range) * (W - M.left - M.right);

    ctx.fillStyle = BLACK; ctx.font = "bold 12px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText("Yearly Returns", 8, 16);

    // Mean line
    ctx.strokeStyle = BLACK; ctx.lineWidth = 0.8;
    ctx.setLineDash([3, 3]);
    const meanX = M.left + ((data.meanYearlyReturn - minR) / range) * (W - M.left - M.right);
    ctx.beginPath(); ctx.moveTo(meanX, M.top); ctx.lineTo(meanX, M.top + yr.length * pH); ctx.stroke();
    ctx.setLineDash([]);
    ctx.fillStyle = BLACK; ctx.font = "8px sans-serif";
    ctx.fillText("Mean", meanX + 2, M.top + 10);

    // Bars
    for (let i = 0; i < yr.length; i++) {
      const y = M.top + i * pH;
      const barW = ((yr[i].return - 0) / range) * (W - M.left - M.right) * (yr[i].return >= 0 ? 1 : -1);
      const bx = yr[i].return >= 0 ? zeroX : zeroX - Math.abs(barW);
      ctx.fillStyle = BLUE;
      ctx.fillRect(bx, y + 2, Math.abs(barW), pH - 4);

      // Year label
      ctx.fillStyle = BLACK; ctx.font = "10px sans-serif";
      ctx.textAlign = "left";
      ctx.fillText(String(yr[i].year), 8, y + pH * 0.5 + 3);

      // Return label
      ctx.textAlign = yr[i].return >= 0 ? "left" : "right";
      const lx = yr[i].return >= 0 ? bx + Math.abs(barW) + 2 : bx - 2;
      ctx.fillText(`${yr[i].return}%`, lx, y + pH * 0.5 + 3);
    }

    // X axis
    ctx.fillStyle = GRAY; ctx.font = "8px sans-serif";
    ctx.textAlign = "center";
    ctx.fillText("Returns", W / 2, H - 2);
    ctx.fillText(`${minR}%`, M.left, H - 2);
    ctx.fillText(`${maxR}%`, M.left + (W - M.left - M.right), H - 2);
  }, [data]);

  // ═══════ Distribution Histogram ═══════
  useEffect(() => {
    if (!data?.monthlyReturnDistribution?.bins?.length) return;
    const canvas = distCanvas.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d")!;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.clientWidth, H = 280;
    canvas.width = W * dpr; canvas.height = H * dpr;
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    ctx.fillStyle = BG; ctx.fillRect(0, 0, W, H);

    const dist = data.monthlyReturnDistribution;
    const M = { top: 25, bot: 30, left: 35, right: 10 };
    const pW = W - M.left - M.right, pH = H - M.top - M.bot;
    const maxCount = Math.max(...dist.bins.map(b => b.count));

    ctx.fillStyle = BLACK; ctx.font = "bold 12px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText("Distribution of Monthly Returns", 8, 16);

    // Mean line
    const allStarts = dist.bins.map(b => b.start);
    const allEnds = dist.bins.map(b => b.end);
    const gMin = Math.min(...allStarts), gMax = Math.max(...allEnds);
    const gRange = gMax - gMin || 1;
    const toX = (v: number) => M.left + ((v - gMin) / gRange) * pW;
    const meanLine = toX(dist.mean);
    ctx.strokeStyle = BLACK; ctx.lineWidth = 0.8;
    ctx.setLineDash([3, 3]);
    ctx.beginPath(); ctx.moveTo(meanLine, M.top); ctx.lineTo(meanLine, M.top + pH); ctx.stroke();
    ctx.setLineDash([]);

    // Bars
    for (const bin of dist.bins) {
      const x = toX(bin.start);
      const w = toX(bin.end) - toX(bin.start);
      const h = (bin.count / maxCount) * pH;
      ctx.fillStyle = bin.count > 0 ? BLUE : "rgba(30,90,168,0.1)";
      ctx.fillRect(x, M.top + pH - h, Math.max(w - 1, 2), h);
    }

    // Axes
    ctx.fillStyle = GRAY; ctx.font = "8px sans-serif";
    ctx.textAlign = "center";
    ctx.fillText("Returns", M.left + pW / 2, H - 2);
    ctx.textAlign = "left";
    ctx.fillText("Occurrences", 2, M.top + pH / 2);
    for (let i = 0; i <= 4; i++) {
      const v = Math.round(i * maxCount / 4);
      ctx.fillText(String(v), 2, M.top + pH - (i / 4) * pH + 3);
    }
  }, [data]);

  // ═══════ QQ Plot ═══════
  useEffect(() => {
    if (!data?.qqPlot?.points?.length) return;
    const canvas = qqCanvas.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d")!;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.clientWidth, H = 280;
    canvas.width = W * dpr; canvas.height = H * dpr;
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    ctx.fillStyle = BG; ctx.fillRect(0, 0, W, H);

    const pts = data.qqPlot.points;
    const M = { top: 25, bot: 30, left: 40, right: 10 };
    const pW = W - M.left - M.right, pH = H - M.top - M.bot;
    const tVals = pts.map(p => p.theoretical);
    const oVals = pts.map(p => p.observed);
    const tMin = -5, tMax = 5, oMin = -5, oMax = 5;

    const toX = (t: number) => M.left + ((t - tMin) / (tMax - tMin)) * pW;
    const toY = (o: number) => M.top + pH - ((o - oMin) / (oMax - oMin)) * pH;

    ctx.fillStyle = BLACK; ctx.font = "bold 12px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText("Normal Distribution Q-Q", 8, 16);

    // Grid
    ctx.strokeStyle = GRID; ctx.lineWidth = 0.5;
    for (let i = 0; i <= 4; i++) {
      const y = M.top + (i / 4) * pH;
      ctx.beginPath(); ctx.moveTo(M.left, y); ctx.lineTo(M.left + pW, y); ctx.stroke();
    }

    // Diagonal line
    ctx.strokeStyle = BLACK; ctx.lineWidth = 0.8;
    ctx.beginPath(); ctx.moveTo(M.left, M.top + pH); ctx.lineTo(M.left + pW, M.top); ctx.stroke();

    // Points
    for (const p of pts) {
      ctx.fillStyle = BLUE;
      ctx.beginPath();
      ctx.arc(toX(p.theoretical), toY(p.observed), 2, 0, Math.PI * 2);
      ctx.fill();
    }

    // Axes
    ctx.fillStyle = GRAY; ctx.font = "8px sans-serif";
    ctx.textAlign = "center";
    ctx.fillText("Normal Distribution Quantile", M.left + pW / 2, H - 2);
    ctx.textAlign = "left";
    ctx.fillText("Observed", M.left + pW + 2, M.top + pH / 2 + 10);
  }, [data]);

  // ═══════ Rolling Stats ═══════
  useEffect(() => {
    if (!data?.rollingStats?.series?.length) return;
    const canvas = rollingCanvas.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d")!;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.clientWidth, H = 300;
    canvas.width = W * dpr; canvas.height = H * dpr;
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    ctx.fillStyle = BG; ctx.fillRect(0, 0, W, H);

    const rs = data.rollingStats;
    const M = { top: 30, bot: 30, left: 45, right: 15 };
    const pW = W - M.left - M.right, pH = H - M.top - M.bot;
    const allVals = rs.series.map(s => s.rollingReturn).concat(rs.series.map(s => s.rollingVolatility));
    const minV = Math.min(...allVals) * 1.1, maxV = Math.max(...allVals) * 1.1;
    const range = maxV - minV || 1;
    const toX = (i: number) => M.left + (i / (rs.series.length - 1)) * pW;
    const toY = (v: number) => M.top + pH - ((v - minV) / range) * pH;

    ctx.fillStyle = BLACK; ctx.font = "bold 12px sans-serif";
    ctx.textAlign = "left";
    ctx.fillText(`Rolling Statistics [${rs.windowMonths} Months]`, 8, 18);

    // Legend
    ctx.fillStyle = BLUE; ctx.font = "10px sans-serif";
    ctx.textAlign = "right";
    ctx.fillText("Rolling Return", W - 8, 14);
    ctx.fillStyle = GRAY;
    ctx.fillText("Rolling Volatility", W - 8, 28);

    // Grid
    ctx.strokeStyle = GRID; ctx.lineWidth = 0.5;
    for (let i = 0; i <= 4; i++) {
      const y = M.top + (i / 4) * pH;
      ctx.beginPath(); ctx.moveTo(M.left, y); ctx.lineTo(M.left + pW, y); ctx.stroke();
    }

    // Volatility line (draw first, behind)
    ctx.strokeStyle = GRAY; ctx.lineWidth = 1;
    ctx.beginPath();
    for (let i = 0; i < rs.series.length; i++) {
      const x = toX(i), y = toY(rs.series[i].rollingVolatility);
      i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    }
    ctx.stroke();

    // Return line
    ctx.strokeStyle = BLUE; ctx.lineWidth = 1.5;
    ctx.beginPath();
    for (let i = 0; i < rs.series.length; i++) {
      const x = toX(i), y = toY(rs.series[i].rollingReturn);
      i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    }
    ctx.stroke();

    // Y axis
    ctx.fillStyle = GRAY; ctx.font = "8px sans-serif"; ctx.textAlign = "right";
    for (let i = 0; i <= 3; i++) {
      const v = Math.round(minV + (i / 3) * range);
      ctx.fillText(`${v}%`, M.left - 4, toY(v) + 3);
    }

    // X axis: years
    ctx.textAlign = "center";
    const years = [...new Set(rs.series.map(s => s.date.slice(0, 4)))];
    for (const yr of years.slice(0, 8)) {
      const pts = rs.series.filter(s => s.date.startsWith(yr));
      if (pts.length) {
        const idx = rs.series.indexOf(pts[Math.floor(pts.length / 2)]);
        ctx.fillText(yr, toX(idx), M.top + pH + 14);
      }
    }
  }, [data]);

  if (loading) return <div className="p-8 text-center text-gray-500">Loading quant report...</div>;
  if (error) return <div className="p-8 text-center text-red-500">Error: {error}</div>;
  if (!data) return null;

  return (
    <div className={`bg-white text-black p-4 max-w-5xl mx-auto ${className}`}>
      {/* Header */}
      <div className="flex items-start justify-between mb-2">
        <div>
          <div className="flex items-center gap-2">
            <div className="w-5 h-5 rounded-full bg-blue-700 flex items-center justify-center">
              <span className="text-[7px] text-white font-bold">QF</span>
            </div>
            <span className="text-[10px] text-gray-500">QF-Lib technology</span>
          </div>
          <p className="text-xs text-gray-400 mt-0.5">Generated with QF-Lib</p>
          <h1 className="text-base font-bold mt-1">{data.meta.strategyName}</h1>
          <p className="text-[10px] text-gray-400">{new Date(data.meta.generatedAt).toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" })}</p>
        </div>
      </div>
      <div className="border-t border-gray-200 mb-4" />

      {/* Row 1: Equity Curve */}
      <div className="mb-4 border border-gray-100 rounded-sm overflow-hidden">
        <canvas ref={equityCanvas} className="w-full" style={{ height: 320 }} />
      </div>

      {/* Row 2: Monthly Returns + Yearly Returns */}
      <div className="grid grid-cols-2 gap-4 mb-4">
        <div className="border border-gray-100 rounded-sm overflow-hidden">
          <canvas ref={monthlyCanvas} className="w-full" style={{ height: 340 }} />
        </div>
        <div className="border border-gray-100 rounded-sm overflow-hidden">
          <canvas ref={yearlyCanvas} className="w-full" style={{ height: 340 }} />
        </div>
      </div>

      {/* Row 3: Distribution + QQ Plot */}
      <div className="grid grid-cols-2 gap-4 mb-4">
        <div className="border border-gray-100 rounded-sm overflow-hidden">
          <canvas ref={distCanvas} className="w-full" style={{ height: 280 }} />
        </div>
        <div className="border border-gray-100 rounded-sm overflow-hidden">
          <canvas ref={qqCanvas} className="w-full" style={{ height: 280 }} />
        </div>
      </div>

      {/* Row 4: Rolling Stats */}
      <div className="border border-gray-100 rounded-sm overflow-hidden mb-2">
        <canvas ref={rollingCanvas} className="w-full" style={{ height: 300 }} />
      </div>

      {/* Footer */}
      <div className="text-right text-[9px] text-gray-400">Page 1 of 2</div>
    </div>
  );
}
