import { useEffect, useRef } from "react";
import { ema } from "@/lib/fx/indicators";
import { PAIRS } from "@/lib/fx/pairs";
import { formatPrice, pairLabel } from "@/lib/fx/format";
import { useDesk } from "@/store/desk";

function readVar(name: string, fallback: string) {
  if (typeof window === "undefined") return fallback;
  const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
  return v || fallback;
}

export function Chart() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const wrapRef = useRef<HTMLDivElement>(null);
  const selected = useDesk((s) => s.selected);

  useEffect(() => {
    const canvas = canvasRef.current;
    const wrap = wrapRef.current;
    if (!canvas || !wrap) return;
    let raf = 0;
    let running = true;
    const mouse = { x: -1, y: -1 };

    const onMove = (e: PointerEvent) => {
      const r = canvas.getBoundingClientRect();
      mouse.x = e.clientX - r.left;
      mouse.y = e.clientY - r.top;
    };
    const onLeave = () => {
      mouse.x = -1;
      mouse.y = -1;
    };
    canvas.addEventListener("pointermove", onMove);
    canvas.addEventListener("pointerleave", onLeave);

    const draw = () => {
      if (!running) return;
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const w = wrap.clientWidth;
      const h = wrap.clientHeight;
      if (w < 8 || h < 8) {
        raf = requestAnimationFrame(draw);
        return;
      }
      if (canvas.width !== Math.floor(w * dpr) || canvas.height !== Math.floor(h * dpr)) {
        canvas.width = Math.floor(w * dpr);
        canvas.height = Math.floor(h * dpr);
        canvas.style.width = `${w}px`;
        canvas.style.height = `${h}px`;
      }
      const ctx = canvas.getContext("2d");
      if (!ctx) return;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);

      const state = useDesk.getState();
      const pairId = state.selected;
      const spec = PAIRS[pairId];
      const m = state.market[pairId];
      const bg = readVar("--color-chart", "#0b0c0e");
      const grid = "rgba(236,236,232,0.06)";
      const muted = readVar("--color-muted-foreground", "#8a8d93");
      const fg = readVar("--color-foreground", "#ecece8");
      const up = readVar("--color-up", "#2f9d78");
      const down = readVar("--color-down", "#c45c54");
      const ring = readVar("--color-ring", "#b8c0c8");

      ctx.fillStyle = bg;
      ctx.fillRect(0, 0, w, h);

      if (!m) {
        raf = requestAnimationFrame(draw);
        return;
      }

      const bars = m.candles.concat(m.forming);
      const vis = bars.slice(-90);
      const padL = 12;
      const padR = 64;
      const padT = 36;
      const padB = 28;
      const plotW = w - padL - padR;
      const plotH = h - padT - padB;
      const slot = plotW / vis.length;
      const body = Math.max(1.5, slot * 0.62);

      let lo = Infinity;
      let hi = -Infinity;
      for (const c of vis) {
        lo = Math.min(lo, c.l);
        hi = Math.max(hi, c.h);
      }
      const posLines = state.positions.filter((p) => p.pair === pairId);
      for (const p of posLines) {
        lo = Math.min(lo, p.entry, p.sl ?? lo, p.tp ?? lo);
        hi = Math.max(hi, p.entry, p.sl ?? hi, p.tp ?? hi);
      }
      const pad = (hi - lo) * 0.08 || spec.pip * 8;
      lo -= pad;
      hi += pad;
      const yOf = (price: number) => padT + ((hi - price) / (hi - lo)) * plotH;

      ctx.strokeStyle = grid;
      ctx.lineWidth = 1;
      ctx.beginPath();
      const steps = 6;
      for (let i = 0; i <= steps; i++) {
        const y = padT + (plotH / steps) * i;
        ctx.moveTo(padL, y);
        ctx.lineTo(w - padR, y);
        const px = hi - ((hi - lo) / steps) * i;
        ctx.font = "10px 'IBM Plex Mono', ui-monospace, monospace";
        ctx.fillStyle = muted;
        ctx.textAlign = "left";
        ctx.textBaseline = "middle";
        ctx.fillText(px.toFixed(spec.digits), w - padR + 8, y);
      }
      ctx.stroke();

      const closes = vis.map((c) => c.c);
      const e8 = ema(closes, 8);
      const e21 = ema(closes, 21);

      const strokeEma = (series: number[], color: string) => {
        ctx.beginPath();
        ctx.strokeStyle = color;
        ctx.lineWidth = 1.1;
        series.forEach((v, i) => {
          const x = padL + i * slot + slot / 2;
          const y = yOf(v);
          if (i === 0) ctx.moveTo(x, y);
          else ctx.lineTo(x, y);
        });
        ctx.stroke();
      };
      strokeEma(e21, "rgba(184,192,200,0.45)");
      strokeEma(e8, "rgba(184,192,200,0.9)");

      vis.forEach((c, i) => {
        const x = padL + i * slot + slot / 2;
        const bull = c.c >= c.o;
        ctx.strokeStyle = bull ? up : down;
        ctx.fillStyle = bull ? up : down;
        ctx.beginPath();
        ctx.moveTo(x, yOf(c.h));
        ctx.lineTo(x, yOf(c.l));
        ctx.stroke();
        const top = yOf(Math.max(c.o, c.c));
        const bot = yOf(Math.min(c.o, c.c));
        const bh = Math.max(1, bot - top);
        ctx.globalAlpha = i === vis.length - 1 ? 0.7 : 1;
        ctx.fillRect(x - body / 2, top, body, bh);
        ctx.globalAlpha = 1;
      });

      for (const p of posLines) {
        dashLine(ctx, yOf(p.entry), padL, w - padR, ring, `${p.side === "buy" ? "LONG" : "SHORT"} ${p.lots.toFixed(2)}`);
        if (p.sl != null) dashLine(ctx, yOf(p.sl), padL, w - padR, down, "SL");
        if (p.tp != null) dashLine(ctx, yOf(p.tp), padL, w - padR, up, "TP");
      }

      const lastY = yOf(m.mid);
      ctx.strokeStyle = m.mid >= vis[0]!.o ? up : down;
      ctx.setLineDash([3, 4]);
      ctx.beginPath();
      ctx.moveTo(padL, lastY);
      ctx.lineTo(w - padR, lastY);
      ctx.stroke();
      ctx.setLineDash([]);
      ctx.fillStyle = m.mid >= vis[0]!.o ? up : down;
      const tag = formatPrice(pairId, m.mid);
      ctx.font = "11px 'IBM Plex Mono', ui-monospace, monospace";
      const tw = ctx.measureText(tag).width + 10;
      ctx.fillRect(w - padR + 4, lastY - 8, tw, 16);
      ctx.fillStyle = "#0b0c0e";
      ctx.textAlign = "left";
      ctx.textBaseline = "middle";
      ctx.fillText(tag, w - padR + 9, lastY);

      ctx.fillStyle = fg;
      ctx.font = "600 13px 'IBM Plex Sans', sans-serif";
      ctx.textAlign = "left";
      ctx.textBaseline = "top";
      ctx.fillText(pairLabel(pairId), padL, 10);
      ctx.font = "12px 'IBM Plex Mono', ui-monospace, monospace";
      ctx.fillStyle = m.mid >= m.dayOpen ? up : down;
      ctx.fillText(formatPrice(pairId, m.mid), padL + 78, 11);
      ctx.fillStyle = muted;
      ctx.font = "10px 'IBM Plex Sans', sans-serif";
      ctx.fillText("M1  ·  SIM  ·  EMA 8 / 21", padL + 170, 13);

      if (mouse.x >= padL && mouse.x <= w - padR && mouse.y >= padT && mouse.y <= h - padB) {
        ctx.strokeStyle = "rgba(236,236,232,0.18)";
        ctx.setLineDash([2, 3]);
        ctx.beginPath();
        ctx.moveTo(mouse.x, padT);
        ctx.lineTo(mouse.x, h - padB);
        ctx.moveTo(padL, mouse.y);
        ctx.lineTo(w - padR, mouse.y);
        ctx.stroke();
        ctx.setLineDash([]);
        const idx = Math.min(vis.length - 1, Math.max(0, Math.floor((mouse.x - padL) / slot)));
        const c = vis[idx]!;
        const price = hi - ((mouse.y - padT) / plotH) * (hi - lo);
        ctx.fillStyle = "rgba(16,18,20,0.92)";
        ctx.fillRect(padL, padT, 168, 64);
        ctx.strokeStyle = grid;
        ctx.strokeRect(padL, padT, 168, 64);
        ctx.fillStyle = fg;
        ctx.font = "11px 'IBM Plex Mono', ui-monospace, monospace";
        ctx.textBaseline = "top";
        ctx.fillText(`O ${c.o.toFixed(spec.digits)}`, padL + 8, padT + 8);
        ctx.fillText(`H ${c.h.toFixed(spec.digits)}`, padL + 8, padT + 22);
        ctx.fillText(`L ${c.l.toFixed(spec.digits)}`, padL + 8, padT + 36);
        ctx.fillText(`C ${c.c.toFixed(spec.digits)}`, padL + 8, padT + 50);
        ctx.fillStyle = muted;
        ctx.fillText(price.toFixed(spec.digits), padL + 96, padT + 8);
      }

      raf = requestAnimationFrame(draw);
    };

    raf = requestAnimationFrame(draw);
    return () => {
      running = false;
      cancelAnimationFrame(raf);
      canvas.removeEventListener("pointermove", onMove);
      canvas.removeEventListener("pointerleave", onLeave);
    };
  }, [selected]);

  return (
    <div ref={wrapRef} className="relative h-full min-h-64 w-full bg-chart">
      <canvas ref={canvasRef} className="block h-full w-full" />
    </div>
  );
}

function dashLine(
  ctx: CanvasRenderingContext2D,
  y: number,
  x0: number,
  x1: number,
  color: string,
  label: string,
) {
  ctx.save();
  ctx.strokeStyle = color;
  ctx.globalAlpha = 0.55;
  ctx.setLineDash([4, 4]);
  ctx.beginPath();
  ctx.moveTo(x0, y);
  ctx.lineTo(x1, y);
  ctx.stroke();
  ctx.setLineDash([]);
  ctx.globalAlpha = 1;
  ctx.fillStyle = color;
  ctx.font = "9px 'IBM Plex Sans', sans-serif";
  ctx.textAlign = "left";
  ctx.textBaseline = "bottom";
  ctx.fillText(label, x0 + 4, y - 2);
  ctx.restore();
}
