"use client";

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

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

export function PolarSmile({ S, K, T, r, q, atmSigma, type, expiries, selectedT, onPickT }: PolarSmileProps) {
  const W = 680, H = 680;
  const cx = W / 2, cy = H / 2;
  const rOuter = 240;
  const eyeR = 64;

  // Strike range ±15% moneyness
  const N = 48;
  const kMin = S * 0.85;
  const kMax = S * 1.15;

  function strikeAt(i: number): number {
    return kMin + (i / N) * (kMax - kMin);
  }

  // Piecewise angle: puts descend LEFT (counterclockwise), calls descend RIGHT (clockwise).
  // ATM → top (−π/2); both wings meet at BOTTOM (−3π/2 ≡ +π/2). Full closed lens.
  function angleFor(K_: number): number {
    if (K_ <= S) {
      const t = (S - K_) / (S - kMin || 1);
      return -Math.PI / 2 - t * Math.PI;
    }
    const t = (K_ - S) / (kMax - S || 1);
    return -Math.PI / 2 + t * Math.PI;
  }

  // Strike tick labels — round multiples of a step fitted to the price range
  const rawStep = (kMax - kMin) / 8;
  const tickStep = rawStep >= 40 ? 50 : rawStep >= 20 ? 25 : rawStep >= 8 ? 10 : 5;
  const tickStrikes: number[] = [];
  for (let kk = Math.ceil(kMin / tickStep) * tickStep; kk <= kMax; kk += tickStep) {
    tickStrikes.push(kk);
  }

  // Dynamic IV range across all expiries → defines radial scale
  const { ivLo, ivHi } = useMemo(() => {
    let lo = Infinity, hi = -Infinity;
    expiries.forEach(e => {
      for (let i = 0; i <= N; i++) {
        const iv = bsSynthIV(S, strikeAt(i), e.T, atmSigma);
        if (iv < lo) lo = iv;
        if (iv > hi) hi = iv;
      }
    });
    return { ivLo: Math.max(0.05, lo - 0.02), ivHi: hi + 0.02 };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [S, atmSigma, expiries]);

  // Radial scale: inner floor 60px, outer wall rOuter
  function ivToR(iv: number): number {
    return 60 + ((iv - ivLo) / (ivHi - ivLo)) * (rOuter - 60);
  }

  // 5 evenly-spaced IV ring labels
  const ivLabels = useMemo(
    () => Array.from({ length: 5 }, (_, step) => ivLo + (step / 4) * (ivHi - ivLo)),
    [ivLo, ivHi]
  );

  // Smooth closed curves (N+1 samples, joined with Z so wings meet at bottom)
  const curves = useMemo(() => {
    return expiries.map(e => {
      const pts: [number, number][] = [];
      for (let i = 0; i <= N; i++) {
        const Kk = strikeAt(i);
        const iv = bsSynthIV(S, Kk, e.T, atmSigma);
        const a = angleFor(Kk);
        const rr = ivToR(iv);
        pts.push([cx + Math.cos(a) * rr, cy + Math.sin(a) * rr]);
      }
      return { expiry: e, pts, isSelected: Math.abs(e.T - selectedT) < 1e-6 };
    });
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [S, atmSigma, expiries, selectedT, ivLo, ivHi]);

  function pathD(pts: [number, number][]): string {
    const inner = pts.map(([px, py]) => `${px.toFixed(2)} ${py.toFixed(2)}`).join(' L ');
    return `M ${inner} Z`;
  }

  function styleFor(idx: number, isSelected: boolean) {
    if (isSelected) return {
      stroke: 'var(--brass-bright)', strokeWidth: 2.5, strokeDasharray: undefined,
      fill: 'rgba(194,170,122,0.12)',
    };
    const strokes = ['var(--fg-1)', 'var(--fg-2)', 'var(--fg-3)', 'var(--fg-4)'];
    const dashes  = [undefined, '4 3', '5 4', '2 4'];
    const widths  = [1.4, 1.2, 1.2, 1.1];
    const i = Math.min(3, idx);
    return { stroke: strokes[i], strokeWidth: widths[i], strokeDasharray: dashes[i], fill: 'none' };
  }

  // Selected expiry object
  const selectedExpiry = expiries.find(e => Math.abs(e.T - selectedT) < 1e-6) ?? expiries[0];

  // Current K dot on selected-expiry curve
  const curIv = bsSynthIV(S, K, selectedExpiry?.T ?? T, atmSigma);
  const aCur = angleFor(K);
  const rCur = ivToR(curIv);
  const dotX = cx + Math.cos(aCur) * rCur;
  const dotY = cy + Math.sin(aCur) * rCur;
  const dotLabelRight = aCur > -Math.PI / 2 && aCur < Math.PI / 2;

  // Fair value + greeks for selected K & expiry
  const selT = selectedExpiry?.T ?? T;
  const fair = useMemo(() => bsPrice(S, K, selT, r, q, atmSigma, type), [S, K, selT, r, q, atmSigma, type]);
  const gr   = useMemo(() => bsGreeks(S, K, selT, r, q, atmSigma, type), [S, K, selT, r, q, atmSigma, type]);

  return (
    <div className="opt-surface">
      <div className="head">
        <h3>Vol Surface <em>polar</em></h3>
      </div>
      <div className="opt-surface-legend">
        {expiries.map((e, idx) => {
          const isSel = Math.abs(e.T - selectedT) < 1e-6;
          const s = styleFor(idx, isSel);
          return (
            <div key={e.label}
              className={`item${isSel ? '' : ' muted'}`}
              onClick={() => onPickT(e.T)}
              style={{ cursor: 'pointer' }}
            >
              <div className="swatch" style={{ background: s.stroke }} />
              {e.label}
            </div>
          );
        })}
      </div>
      <div className="opt-polar-wrap">
        <svg viewBox={`0 0 ${W} ${H}`} width="100%" className="opt-polar" style={{ display: 'block' }}>

          {/* Concentric IV rings */}
          {ivLabels.map((iv, i) => (
            <circle key={i}
              className={`ring${i === ivLabels.length - 1 ? ' outer' : ''}`}
              cx={cx} cy={cy} r={ivToR(iv)} />
          ))}
          {ivLabels.map((iv, i) => (
            <text key={`l${i}`} className="iv" x={cx + 6} y={(cy - ivToR(iv) - 2).toFixed(1)}>
              {(iv * 100).toFixed(0)}%
            </text>
          ))}

          {/* Spoke lines + round strike tick labels */}
          {tickStrikes.map(k => {
            const a = angleFor(k);
            const isAtm = Math.abs(k - S) < 2.5;
            const x2 = cx + Math.cos(a) * rOuter;
            const y2 = cy + Math.sin(a) * rOuter;
            const lx = cx + Math.cos(a) * (rOuter + 18);
            const ly = cy + Math.sin(a) * (rOuter + 18);
            return (
              <g key={k}>
                <line
                  className={`spoke${isAtm ? ' atm' : ''}`}
                  x1={cx} y1={cy}
                  x2={x2.toFixed(1)} y2={y2.toFixed(1)}
                  style={{ opacity: isAtm ? 1 : 0.35 }}
                />
                <text x={lx.toFixed(1)} y={(ly + 3).toFixed(1)}
                  textAnchor="middle"
                  className={`tick${isAtm ? ' atm' : ''}`}>
                  {k.toFixed(0)}
                </text>
              </g>
            );
          })}

          {/* Directional labels */}
          <text x={(cx - rOuter - 6).toFixed(1)} y={cy} textAnchor="end"
            style={{ fontFamily: 'var(--font-sans)', fontSize: 10, letterSpacing: 'var(--tr-wider)', textTransform: 'uppercase', fill: 'var(--negative)' }}>
            OTM puts ↓
          </text>
          <text x={(cx + rOuter + 6).toFixed(1)} y={cy} textAnchor="start"
            style={{ fontFamily: 'var(--font-sans)', fontSize: 10, letterSpacing: 'var(--tr-wider)', textTransform: 'uppercase', fill: 'var(--positive)' }}>
            ↓ OTM calls
          </text>
          <text x={cx} y={(cy - rOuter - 24).toFixed(1)} textAnchor="middle"
            style={{ fontFamily: 'var(--font-sans)', fontSize: 10, letterSpacing: 'var(--tr-wider)', textTransform: 'uppercase', fill: 'var(--brass)' }}>
            ATM ↑
          </text>

          {/* Expiry curves — closed lens shape */}
          {curves.map((c, idx) => {
            const s = styleFor(idx, c.isSelected);
            const d = pathD(c.pts);
            return (
              <g key={idx}>
                {c.isSelected && (
                  <path d={d} className="expiry-fill" fill={s.fill} stroke="none" />
                )}
                <path d={d} className="expiry"
                  stroke={s.stroke}
                  strokeWidth={s.strokeWidth}
                  strokeDasharray={s.strokeDasharray}
                  fill="none"
                  style={{ cursor: 'pointer' }}
                  onClick={() => onPickT(c.expiry.T)}
                />
              </g>
            );
          })}

          {/* Dashed spoke from center to selected-K marker */}
          <line className="marker-line" x1={cx} y1={cy} x2={dotX.toFixed(1)} y2={dotY.toFixed(1)} />

          {/* Selected-K dot */}
          <circle cx={dotX.toFixed(1)} cy={dotY.toFixed(1)} r={6} className="dot" />

          {/* K label */}
          <text
            x={(dotX + (dotLabelRight ? 10 : -10)).toFixed(1)}
            y={(dotY + 4).toFixed(1)}
            textAnchor={dotLabelRight ? 'start' : 'end'}
            className="brass" style={{ fontSize: 12 }}
          >
            K {K.toFixed(0)} · {(curIv * 100).toFixed(1)}%
          </text>

          {/* Center eye */}
          <circle cx={cx} cy={cy} r={eyeR} className="eye" />
          <text x={cx} y={(cy - 30).toFixed(1)} textAnchor="middle" className="eye-lbl">
            {type === 'C' ? 'call · fair' : 'put · fair'}
          </text>
          <text x={cx} y={(cy - 4).toFixed(1)} textAnchor="middle" className="eye-num" style={{ fontSize: 30 }}>
            {fair.toFixed(2)}
          </text>
          <text x={cx} y={(cy + 16).toFixed(1)} textAnchor="middle"
            style={{ fontFamily: 'var(--font-mono)', fontSize: 10, fill: 'var(--fg-2)' }}>
            Δ {gr.delta.toFixed(2)} · ν {gr.vega.toFixed(2)}
          </text>
          <text x={cx} y={(cy + 32).toFixed(1)} textAnchor="middle" className="eye-lbl" style={{ fontSize: 9 }}>
            {selectedExpiry?.label} · {selectedExpiry?.dte}d
          </text>
        </svg>
      </div>
    </div>
  );
}

interface IvHeatmapProps {
  S: number;
  atmSigma: number;
  expiries: Expiry[];
  selectedExpiryIdx: number;
  selectedK: number;
  onSelect: (expiryIdx: number, K: number) => void;
}

export function IvHeatmap({ S, atmSigma, expiries, selectedExpiryIdx, selectedK, onSelect }: IvHeatmapProps) {
  const nStrikes = 13;
  const kMin = S * 0.85, kMax = S * 1.15;

  const strikes = useMemo(() => {
    const arr: number[] = [];
    for (let i = 0; i < nStrikes; i++) {
      arr.push(Math.round((kMin + (kMax - kMin) * i / (nStrikes - 1)) / 5) * 5);
    }
    return arr;
  }, [kMin, kMax]);

  const ivGrid = useMemo(() => {
    return expiries.map(e =>
      strikes.map(K => bsSynthIV(S, K, e.T, atmSigma))
    );
  }, [S, atmSigma, expiries, strikes]);

  const allIvs = ivGrid.flat();
  const ivGridMin = Math.min(...allIvs);
  const ivGridMax = Math.max(...allIvs);

  function cellColor(iv: number): string {
    const pct = Math.round(((iv - ivGridMin) / (ivGridMax - ivGridMin + 0.001)) * 80);
    return `color-mix(in oklch, var(--ink-2), var(--brass-deep) ${pct}%)`;
  }

  function textColor(iv: number): string {
    const pct = (iv - ivGridMin) / (ivGridMax - ivGridMin + 0.001);
    return pct > 0.5 ? 'var(--fg-1)' : 'var(--fg-3)';
  }

  const atmK = Math.round(S / 5) * 5;

  return (
    <div className="opt-surface">
      <div className="head">
        <h3>IV Heatmap <em>surface</em></h3>
      </div>
      <div className="opt-heat">
        <div className="ylabs">
          {expiries.map(e => (
            <span key={e.label}>{e.label}</span>
          ))}
        </div>
        <div>
          <div className="grid" style={{ gridTemplateColumns: `repeat(${nStrikes}, 1fr)` }}>
            {ivGrid.map((row, eIdx) =>
              row.map((iv, kIdx) => {
                const K = strikes[kIdx];
                const isCursor = eIdx === selectedExpiryIdx && K === selectedK;
                return (
                  <div
                    key={`${eIdx}-${kIdx}`}
                    className={`cell${isCursor ? ' cursor' : ''}`}
                    style={{ background: cellColor(iv), color: textColor(iv) }}
                    onClick={() => onSelect(eIdx, K)}
                  >
                    {(iv * 100).toFixed(0)}%
                  </div>
                );
              })
            )}
          </div>
          <div className="xlabs" style={{ gridTemplateColumns: `repeat(${nStrikes}, 1fr)` }}>
            {strikes.map((K, i) => (
              <span key={i} className={K === atmK ? 'atm' : ''}>{K}</span>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}
