"use client";

import { useEffect, useRef, useState, useMemo } from "react";
import { useHyperliquidWebSocket, type L2Snapshot, type TradeTapeEntry } from "@/lib/hyperliquid-ws";

// ═══════════════════════ Color Palette ═══════════════════════
const BID_COLOR = "#00C853";
const ASK_COLOR = "#FF1744";
const MID_COLOR = "#FFEB3B";
const TRADE_PATH = "#FFAB00";
const TEXT_COLOR = "#CCCCCC";
const TEXT_BRIGHT = "#FFFFFF";
const BG_COLOR = "#000000";
const GRID_COLOR = "rgba(255,255,255,0.04)";

// ═══════════════════════ Quant Overlay Types ═══════════════════════
export interface QuantOverlay {
  /** Horizontal line at a fair value price */
  fairValue?: number;
  /** VWAP band: { mid, upper, lower } */
  vwap?: { mid: number; upper: number; lower: number };
  /** Imbalance annotation point */
  imbalance?: { value: number; label: string };
  /** Custom signal markers at specific prices */
  signals?: { px: number; label: string; color: string }[];
}

interface Props {
  coin?: string;
  height?: number;
  topRatio?: number; // fraction for L2 panel (0-1)
  overlays?: QuantOverlay;
  className?: string;
}

export default function OrderBookDepthMap({
  coin = "BTC",
  height = 600,
  topRatio = 0.55,
  overlays,
  className = "",
}: Props) {
  const topCanvas = useRef<HTMLCanvasElement>(null);
  const botCanvas = useRef<HTMLCanvasElement>(null);
  const topH = Math.round(height * topRatio);
  const botH = height - topH - 2;

  const { l2, trades, connected, error } = useHyperliquidWebSocket(coin);

  // ── L2 Profile Render ──
  useEffect(() => {
    const canvas = topCanvas.current;
    if (!canvas || !l2) 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);

    // Background
    ctx.fillStyle = BG_COLOR;
    ctx.fillRect(0, 0, W, H);

    const margin = { top: 20, bottom: 30, left: 60, right: 60 };
    const plotW = W - margin.left - margin.right;
    const plotH = H - margin.top - margin.bottom;

    // Price range: center on mid, show ±2% on each side
    const mid = l2.mid;
    const priceRange = mid * 0.04; // ±2%
    const pMin = mid - priceRange;
    const pMax = mid + priceRange;

    // Find max volume for scaling
    const allVols = [
      ...l2.bids.slice(0, 100).map((l) => l.sz),
      ...l2.asks.slice(0, 100).map((l) => l.sz),
    ];
    const maxVol = Math.max(...allVols, 1);
    const volScale = Math.max(maxVol * 1.2, 10);

    const priceToX = (px: number) => margin.left + ((px - pMin) / (pMax - pMin)) * plotW;
    const volToH = (sz: number) => (sz / volScale) * plotH;

    // Grid lines
    ctx.strokeStyle = GRID_COLOR;
    ctx.lineWidth = 1;
    const gridSteps = 10;
    for (let i = 0; i <= gridSteps; i++) {
      const y = margin.top + (i / gridSteps) * plotH;
      ctx.beginPath();
      ctx.moveTo(margin.left, y);
      ctx.lineTo(margin.left + plotW, y);
      ctx.stroke();
    }

    // Draw bid bars (green, right-to-left from mid)
    for (const bid of l2.bids.slice(0, 100)) {
      if (bid.px > mid + 50) continue; // Skip far bids
      const x = priceToX(bid.px);
      const barW = Math.max(1, plotW / 200);
      const barH = volToH(bid.sz);
      const y = margin.top + plotH - barH;

      ctx.fillStyle = BID_COLOR;
      ctx.fillRect(x - barW / 2, y, barW, barH);
    }

    // Draw ask bars (red, left-to-right from mid)
    for (const ask of l2.asks.slice(0, 100)) {
      if (ask.px < mid - 50) continue;
      const x = priceToX(ask.px);
      const barW = Math.max(1, plotW / 200);
      const barH = volToH(ask.sz);
      const y = margin.top + plotH - barH;

      ctx.fillStyle = ASK_COLOR;
      ctx.fillRect(x - barW / 2, y, barW, barH);
    }

    // Mid-price line
    const midX = priceToX(mid);
    ctx.strokeStyle = MID_COLOR;
    ctx.lineWidth = 1.5;
    ctx.setLineDash([4, 4]);
    ctx.beginPath();
    ctx.moveTo(midX, margin.top);
    ctx.lineTo(midX, margin.top + plotH);
    ctx.stroke();
    ctx.setLineDash([]);

    // Volume scale labels (right side)
    ctx.fillStyle = TEXT_COLOR;
    ctx.font = "9px monospace";
    ctx.textAlign = "right";
    for (let i = 0; i <= 4; i++) {
      const vol = Math.round((volScale * i) / 4);
      const y = margin.top + plotH - (i / 4) * plotH;
      ctx.fillText(vol.toLocaleString(), W - 4, y + 3);
    }

    // Price labels (bottom)
    ctx.textAlign = "center";
    const priceLabels = 6;
    for (let i = 0; i <= priceLabels; i++) {
      const px = pMin + (i / priceLabels) * priceRange;
      const x = priceToX(px);
      ctx.fillText(px.toFixed(1), x, H - 4);
    }

    // Mid price marker (floating)
    ctx.fillStyle = TEXT_BRIGHT;
    ctx.font = "bold 11px monospace";
    ctx.textAlign = "center";
    ctx.fillText(mid.toFixed(1), midX, margin.top + plotH / 2 - 12);
    ctx.fillText(mid.toFixed(1), midX, margin.top + plotH / 2 + 18);

    // Orange dot at mid baseline
    ctx.fillStyle = "#FF9100";
    ctx.beginPath();
    ctx.arc(midX, margin.top + plotH, 3, 0, Math.PI * 2);
    ctx.fill();

    // ── Quant Overlays ──
    if (overlays) {
      // Fair value line
      if (overlays.fairValue) {
        const fvX = priceToX(overlays.fairValue);
        ctx.strokeStyle = "rgba(33, 150, 243, 0.7)";
        ctx.lineWidth = 1;
        ctx.setLineDash([3, 6]);
        ctx.beginPath();
        ctx.moveTo(fvX, margin.top);
        ctx.lineTo(fvX, margin.top + plotH);
        ctx.stroke();
        ctx.setLineDash([]);
        ctx.fillStyle = "#2196F3";
        ctx.font = "9px monospace";
        ctx.textAlign = "center";
        ctx.fillText("FV", fvX, margin.top - 4);
      }

      // VWAP bands
      if (overlays.vwap) {
        for (const [px, color] of [
          [overlays.vwap.upper, "rgba(255,152,0,0.4)"],
          [overlays.vwap.mid, "rgba(255,152,0,0.6)"],
          [overlays.vwap.lower, "rgba(255,152,0,0.4)"],
        ] as const) {
          const vx = priceToX(px);
          ctx.strokeStyle = color;
          ctx.lineWidth = 1;
          ctx.beginPath();
          ctx.moveTo(vx, margin.top);
          ctx.lineTo(vx, margin.top + plotH);
          ctx.stroke();
        }
      }

      // Signal markers
      if (overlays.signals) {
        for (const sig of overlays.signals) {
          const sx = priceToX(sig.px);
          ctx.fillStyle = sig.color;
          ctx.beginPath();
          ctx.arc(sx, margin.top + 15, 4, 0, Math.PI * 2);
          ctx.fill();
          ctx.fillStyle = TEXT_BRIGHT;
          ctx.font = "8px monospace";
          ctx.textAlign = "center";
          ctx.fillText(sig.label, sx, margin.top + 10);
        }
      }
    }

    // Header
    ctx.fillStyle = TEXT_COLOR;
    ctx.font = "10px monospace";
    ctx.textAlign = "left";
    ctx.fillText(`L2 Order Book \u00B7 ${coin}-USD \u00B7 LIVE`, 8, 12);
    ctx.fillStyle = connected ? "#00C853" : "#FF1744";
    ctx.fillText(connected ? "\u25CF" : "\u25CF", W - 18, 12);
  }, [l2, connected, coin, overlays, topH]);

  // ── Trade Tape Render ──
  useEffect(() => {
    const canvas = botCanvas.current;
    if (!canvas || trades.length < 2) 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);

    // Background
    ctx.fillStyle = "#0A0A0A"; // Slightly lighter than pure black
    ctx.fillRect(0, 0, W, H);

    const margin = { top: 20, bottom: 15, left: 8, right: 8 };
    const plotW = W - margin.left - margin.right;
    const plotH = H - margin.top - margin.bottom;

    // Find price range
    const prices = trades.map((t) => t.px);
    const pMin = Math.min(...prices);
    const pMax = Math.max(...prices);
    const pRange = pMax - pMin || 1;
    const pPad = pRange * 0.1 || 10;
    const pLo = pMin - pPad;
    const pHi = pMax + pPad;

    const priceToY = (px: number) => margin.top + plotH - ((px - pLo) / (pHi - pLo)) * plotH;

    // Draw trade path
    ctx.strokeStyle = TRADE_PATH;
    ctx.lineWidth = 1.2;
    ctx.beginPath();
    for (let i = 0; i < trades.length; i++) {
      const x = margin.left + (i / trades.length) * plotW;
      const y = priceToY(trades[i].px);
      if (i === 0) ctx.moveTo(x, y);
      else ctx.lineTo(x, y);
    }
    ctx.stroke();

    // Draw individual trade markers
    const maxSz = Math.max(...trades.map((t) => t.sz), 1);
    for (const trade of trades) {
      const idx = trades.indexOf(trade);
      const x = margin.left + (idx / trades.length) * plotW;
      const y = priceToY(trade.px);
      const r = Math.max(1, (trade.sz / maxSz) * 3 + 1);

      const color = trade.side === "buy" ? "#66BB6A" : "#EF5350";
      ctx.fillStyle = color;
      ctx.globalAlpha = 0.7;
      ctx.beginPath();
      ctx.arc(x, y, r, 0, Math.PI * 2);
      ctx.fill();
      ctx.globalAlpha = 1;
    }

    // Latest trade marker
    const lastTrade = trades[trades.length - 1];
    const lx = margin.left + ((trades.length - 1) / trades.length) * plotW;
    const ly = priceToY(lastTrade.px);
    ctx.strokeStyle = lastTrade.side === "buy" ? "#00E676" : "#FF5252";
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.arc(lx, ly, 4, 0, Math.PI * 2);
    ctx.stroke();

    // Latest price label
    ctx.fillStyle = TEXT_BRIGHT;
    ctx.font = "10px monospace";
    ctx.textAlign = "left";
    const sideLabel = lastTrade.side === "buy" ? "B" : "S";
    const sideColor = lastTrade.side === "buy" ? "#00E676" : "#FF5252";
    ctx.fillStyle = sideColor;
    ctx.fillText(`${sideLabel} ${lastTrade.px.toFixed(1)}`, 8, 12);
    ctx.fillStyle = TEXT_COLOR;
    ctx.fillText(` | ${lastTrade.sz.toFixed(4)}`, 80, 12);

    // Header
    ctx.fillStyle = TEXT_COLOR;
    ctx.font = "9px monospace";
    ctx.textAlign = "right";
    ctx.fillText(`Trades \u00B7 ${trades.length}`, W - 8, 12);
  }, [trades]);

  // ── Empty states ──
  const noL2 = !l2 && !error;

  return (
    <div className={`bg-black ${className}`} style={{ height }}>
      {/* Top: L2 Volume Profile */}
      <div style={{ height: topH }} className="relative">
        <canvas ref={topCanvas} className="w-full h-full" />
        {noL2 && (
          <div className="absolute inset-0 flex items-center justify-center">
            <span className="text-gray-500 text-xs font-mono">
              {connected ? "Waiting for L2 data..." : "Connecting to Hyperliquid..."}
            </span>
          </div>
        )}
        {error && (
          <div className="absolute top-1 right-1 text-red-500 text-[9px] font-mono">
            {error} — reconnecting...
          </div>
        )}
      </div>

      {/* Bottom: Trade Tape */}
      <div style={{ height: botH }} className="relative">
        <canvas ref={botCanvas} className="w-full h-full" />
        {trades.length < 2 && !error && (
          <div className="absolute inset-0 flex items-center justify-center">
            <span className="text-gray-600 text-xs font-mono">Waiting for trades...</span>
          </div>
        )}
      </div>
    </div>
  );
}
