"use client";

import { useMemo } from "react";
import { bsPrice, bsGreeks, bsSynthIV } from "@/lib/blackScholes";
import type { Expiry, OptionType } from "./types";

function smoothPath(pts: [number, number][]): string {
  if (pts.length < 2) return "";
  let d = `M ${pts[0][0]} ${pts[0][1]}`;
  for (let i = 1; i < pts.length; i++) {
    const [x0, y0] = pts[i - 1];
    const [x1, y1] = pts[i];
    const cx = (x0 + x1) / 2;
    d += ` C ${cx} ${y0}, ${cx} ${y1}, ${x1} ${y1}`;
  }
  return d;
}

function linePath(pts: [number, number][]): string {
  if (!pts.length) return "";
  return pts.map(([x, y], i) => `${i === 0 ? 'M' : 'L'} ${x} ${y}`).join(' ');
}

interface SmileChartProps {
  S: number;
  T: number;
  r: number;
  q: number;
  atmSigma: number;
  K: number;
  type: OptionType;
  expiryLabel: string;
  allExpiries: Expiry[];
}

export function SmileChart({ S, T, atmSigma, K, allExpiries }: SmileChartProps) {
  const W = 720, H = 240;
  const pad = { l: 40, r: 20, t: 20, b: 30 };
  const iW = W - pad.l - pad.r;
  const iH = H - pad.t - pad.b;

  const kMin = S * 0.80, kMax = S * 1.22;
  const nPts = 60;

  const primaryPts = useMemo((): [number, number][] => {
    const pts: [number, number][] = [];
    for (let i = 0; i <= nPts; i++) {
      const strike = kMin + (kMax - kMin) * i / nPts;
      const iv = bsSynthIV(S, strike, T, atmSigma);
      pts.push([strike, iv]);
    }
    return pts;
  }, [S, T, atmSigma, kMin, kMax]);

  const otherCurves = useMemo(() => {
    return allExpiries
      .filter(e => Math.abs(e.T - T) > 0.001)
      .slice(0, 3)
      .map(e => {
        const pts: [number, number][] = [];
        for (let i = 0; i <= nPts; i++) {
          const strike = kMin + (kMax - kMin) * i / nPts;
          const iv = bsSynthIV(S, strike, e.T, atmSigma);
          pts.push([strike, iv]);
        }
        return pts;
      });
  }, [S, T, atmSigma, allExpiries, kMin, kMax]);

  const allIvs = primaryPts.map(p => p[1]);
  const ivMin = Math.max(0, Math.min(...allIvs) - 0.02);
  const ivMax = Math.max(...allIvs) + 0.04;

  function toX(strike: number) {
    return pad.l + ((strike - kMin) / (kMax - kMin)) * iW;
  }
  function toY(iv: number) {
    return pad.t + iH - ((iv - ivMin) / (ivMax - ivMin)) * iH;
  }

  const svgPrimary = smoothPath(primaryPts.map(([k, iv]) => [toX(k), toY(iv)] as [number, number]));
  const fillPath = svgPrimary + ` L ${toX(kMax)} ${pad.t + iH} L ${toX(kMin)} ${pad.t + iH} Z`;
  const kX = toX(K);
  const kIv = bsSynthIV(S, K, T, atmSigma);
  const kY = toY(kIv);
  const atmX = toX(S);

  const yTicks = 4;
  const yLabels: number[] = [];
  for (let i = 0; i <= yTicks; i++) {
    yLabels.push(ivMin + (ivMax - ivMin) * i / yTicks);
  }

  return (
    <div className="opt-chart-card opt-svg">
      <div className="head">
        <h4>Vol Smile</h4>
        <span className="eyebrow">Implied Volatility vs. Strike</span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} style={{ display: 'block' }}>
        {yLabels.map(iv => (
          <g key={iv}>
            <line className="grid" x1={pad.l} y1={toY(iv)} x2={pad.l + iW} y2={toY(iv)} />
            <text x={pad.l - 4} y={toY(iv) + 4} textAnchor="end" className="opt-svg">{(iv * 100).toFixed(0)}%</text>
          </g>
        ))}
        <line className="axis" x1={pad.l} y1={pad.t} x2={pad.l} y2={pad.t + iH} />
        <line className="axis" x1={pad.l} y1={pad.t + iH} x2={pad.l + iW} y2={pad.t + iH} />
        {otherCurves.map((pts, idx) => (
          <path
            key={idx}
            className={idx === 0 ? 'curve fade1' : 'curve fade2'}
            d={smoothPath(pts.map(([k, iv]) => [toX(k), toY(iv)] as [number, number]))}
          />
        ))}
        <path className="curve fill" d={fillPath} />
        <path className="curve accent" d={svgPrimary} />
        <line className="spoke" x1={atmX} y1={pad.t} x2={atmX} y2={pad.t + iH} strokeDasharray="3 3" stroke="var(--brass)" strokeWidth="1" />
        <text x={atmX} y={pad.t - 6} textAnchor="middle" className="atm">ATM</text>
        <line className="crosshair" x1={kX} y1={pad.t} x2={kX} y2={pad.t + iH} />
        <circle cx={kX} cy={kY} r={4} className="marker" />
        <text x={kX + 6} y={kY - 6} className="brass">{(kIv * 100).toFixed(1)}%</text>
      </svg>
    </div>
  );
}

interface TermStructureProps {
  S: number;
  r: number;
  q: number;
  atmSigma: number;
  expiries: Expiry[];
  selectedT: number;
  onPickT: (T: number) => void;
}

export function TermStructure({ S, atmSigma, expiries, selectedT, onPickT }: TermStructureProps) {
  const W = 360, H = 150;
  const pad = { l: 36, r: 16, t: 16, b: 30 };
  const iW = W - pad.l - pad.r;
  const iH = H - pad.t - pad.b;

  const pts = useMemo(() => expiries.map(e => {
    const iv = bsSynthIV(S, S, e.T, atmSigma);
    return { T: e.T, sqrtT: Math.sqrt(e.T), iv, label: e.label, dte: e.dte };
  }), [S, atmSigma, expiries]);

  const xs = pts.map(p => p.sqrtT);
  const ivs = pts.map(p => p.iv);
  const xMin = Math.min(...xs), xMax = Math.max(...xs);
  const ivMin = Math.min(...ivs) - 0.01, ivMax = Math.max(...ivs) + 0.01;

  function toX(sqrtT: number) {
    return pad.l + ((sqrtT - xMin) / (xMax - xMin + 0.001)) * iW;
  }
  function toY(iv: number) {
    return pad.t + iH - ((iv - ivMin) / (ivMax - ivMin + 0.001)) * iH;
  }

  const linePts: [number, number][] = pts.map(p => [toX(p.sqrtT), toY(p.iv)]);

  return (
    <div className="opt-chart-card opt-svg">
      <div className="head">
        <h4>Term Structure</h4>
        <span className="eyebrow">ATM IV vs. Expiry</span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} style={{ display: 'block' }}>
        <line className="axis" x1={pad.l} y1={pad.t} x2={pad.l} y2={pad.t + iH} />
        <line className="axis" x1={pad.l} y1={pad.t + iH} x2={pad.l + iW} y2={pad.t + iH} />
        <path className="curve fade1" d={linePath(linePts)} />
        {pts.map((p) => {
          const cx = toX(p.sqrtT);
          const cy = toY(p.iv);
          const isSel = Math.abs(p.T - selectedT) < 0.001;
          return (
            <g key={p.label} style={{ cursor: 'pointer' }} onClick={() => onPickT(p.T)}>
              <circle
                cx={cx} cy={cy} r={isSel ? 5 : 4}
                fill={isSel ? 'var(--brass-bright)' : 'var(--fg-3)'}
                stroke="var(--ink-0)" strokeWidth="1.5"
              />
              <text x={cx} y={pad.t + iH + 14} textAnchor="middle" fontSize="9">{p.label}</text>
            </g>
          );
        })}
      </svg>
    </div>
  );
}

interface GreekMiniProps {
  name: string;
  glyph: string;
  kind: 'delta' | 'gamma' | 'vega' | 'theta';
  S: number;
  K: number;
  T: number;
  r: number;
  q: number;
  sigma: number;
  type: OptionType;
}

export function GreekMini({ name, glyph, kind, S, K, T, r, q, sigma, type }: GreekMiniProps) {
  const W = 160, H = 90;
  const pad = { l: 8, r: 8, t: 8, b: 8 };
  const iW = W - pad.l - pad.r;
  const iH = H - pad.t - pad.b;

  const nPts = 40;

  const pts = useMemo((): [number, number][] => {
    const sMin = S * 0.75, sMax = S * 1.25;
    const result: [number, number][] = [];
    for (let i = 0; i <= nPts; i++) {
      const spot = sMin + (sMax - sMin) * i / nPts;
      const g = bsGreeks(spot, K, T, r, q, sigma, type);
      result.push([spot, g[kind]]);
    }
    return result;
  }, [S, K, T, r, q, sigma, type, kind]);

  const ys = pts.map(p => p[1]);
  const yMin = Math.min(...ys), yMax = Math.max(...ys);
  const xMin = pts[0][0], xMax = pts[pts.length - 1][0];

  function toX(v: number) { return pad.l + ((v - xMin) / (xMax - xMin + 0.001)) * iW; }
  function toY(v: number) { return pad.t + iH - ((v - yMin) / (yMax - yMin + 0.001)) * iH; }

  const svgPts: [number, number][] = pts.map(([x, y]) => [toX(x), toY(y)]);
  const curValG = bsGreeks(S, K, T, r, q, sigma, type);
  const curVal = curValG[kind];

  const dotX = toX(S);
  const dotY = toY(curVal);

  return (
    <div className="opt-greek-mini">
      <div className="lbl">
        <span>{glyph} {name}</span>
        <span className="v">{curVal.toFixed(4)}</span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} style={{ display: 'block' }} className="opt-svg">
        <path className="curve accent" d={smoothPath(svgPts)} />
        <circle cx={dotX} cy={dotY} r={3} className="marker" />
      </svg>
    </div>
  );
}

interface PayoffProps {
  S: number;
  K: number;
  T: number;
  r: number;
  q: number;
  sigma: number;
  type: OptionType;
  mid?: number;
}

export function Payoff({ S, K, T, r, q, sigma, type, mid }: PayoffProps) {
  const W = 720, H = 140;
  const pad = { l: 44, r: 16, t: 16, b: 28 };
  const iW = W - pad.l - pad.r;
  const iH = H - pad.t - pad.b;

  const premium = mid ?? bsPrice(S, K, T, r, q, sigma, type);

  const sMin = S * 0.70, sMax = S * 1.30;
  const nPts = 80;

  const pnlPts = useMemo((): [number, number][] => {
    const pts: [number, number][] = [];
    for (let i = 0; i <= nPts; i++) {
      const spot = sMin + (sMax - sMin) * i / nPts;
      const payoff = type === 'C' ? Math.max(spot - K, 0) : Math.max(K - spot, 0);
      pts.push([spot, payoff - premium]);
    }
    return pts;
  }, [K, type, premium, sMin, sMax]);

  const ys = pnlPts.map(p => p[1]);
  const yMin = Math.min(...ys, -premium * 1.1);
  const yMax = Math.max(...ys, premium * 1.1);

  function toX(v: number) { return pad.l + ((v - sMin) / (sMax - sMin)) * iW; }
  function toY(v: number) { return pad.t + iH - ((v - yMin) / (yMax - yMin + 0.001)) * iH; }

  const zeroY = toY(0);
  const gainPts = pnlPts.filter(p => p[1] >= 0);
  const lossPts = pnlPts.filter(p => p[1] <= 0);

  const allSvg = linePath(pnlPts.map(([x, y]) => [toX(x), toY(y)] as [number, number]));
  const gainArea = gainPts.length > 1
    ? linePath(gainPts.map(([x, y]) => [toX(x), toY(y)] as [number, number])) +
      ` L ${toX(gainPts[gainPts.length - 1][0])} ${zeroY} L ${toX(gainPts[0][0])} ${zeroY} Z`
    : '';
  const lossArea = lossPts.length > 1
    ? linePath(lossPts.map(([x, y]) => [toX(x), toY(y)] as [number, number])) +
      ` L ${toX(lossPts[lossPts.length - 1][0])} ${zeroY} L ${toX(lossPts[0][0])} ${zeroY} Z`
    : '';

  const beSpot = type === 'C' ? K + premium : K - premium;
  const beX = toX(beSpot);
  const spotX = toX(S);
  const kX = toX(K);

  return (
    <div className="opt-payoff opt-svg">
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} style={{ display: 'block' }}>
        <line className="grid" x1={pad.l} y1={zeroY} x2={pad.l + iW} y2={zeroY} />
        {gainArea && (
          <path d={gainArea} fill="var(--positive)" opacity="0.18" />
        )}
        {lossArea && (
          <path d={lossArea} fill="var(--negative)" opacity="0.18" />
        )}
        <path className="curve accent" d={allSvg} />
        <line className="marker-line" x1={kX} y1={pad.t} x2={kX} y2={pad.t + iH} />
        <text x={kX} y={pad.t + iH + 16} textAnchor="middle">K={K.toFixed(0)}</text>
        <line x1={spotX} y1={pad.t} x2={spotX} y2={pad.t + iH} stroke="var(--fg-3)" strokeWidth="1" strokeDasharray="2 3" />
        <text x={spotX} y={pad.t - 4} textAnchor="middle" className="brass">S</text>
        {beSpot >= sMin && beSpot <= sMax && (
          <>
            <line className="marker-line" x1={beX} y1={pad.t} x2={beX} y2={pad.t + iH} />
            <text x={beX} y={pad.t + 14} textAnchor="middle" className="brass">BE</text>
          </>
        )}
      </svg>
    </div>
  );
}
