"use client";

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

interface PolarSmileProps {
  S: number;
  r: number;
  q: number;
  atmSigma: number;
  K: number;
  T: number;
  type: OptionType;
  expiries: Expiry[];
  selectedExpiryIdx: number;
}

export function PolarSmile({ S, r, q, atmSigma, K, T, type, expiries, selectedExpiryIdx }: PolarSmileProps) {
  const SIZE = 680;
  const cx = SIZE / 2, cy = SIZE / 2;
  const maxR = SIZE * 0.42;

  const ivMin = 0.04, ivMax = 0.8;
  const ivRings = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6];

  const kMin = S * 0.82, kMax = S * 1.18;
  const nSpokes = 13;
  const strikes = useMemo(() => {
    const arr: number[] = [];
    for (let i = 0; i < nSpokes; i++) {
      arr.push(kMin + (kMax - kMin) * i / (nSpokes - 1));
    }
    return arr;
  }, [kMin, kMax]);

  function strikeToAngle(strike: number): number {
    const norm = (strike - kMin) / (kMax - kMin);
    return -Math.PI / 2 + (norm - 0.5) * Math.PI * 1.5;
  }

  function ivToR(iv: number): number {
    return maxR * Math.max(0, Math.min(1, (iv - ivMin) / (ivMax - ivMin)));
  }

  function polarToXY(angle: number, radius: number): [number, number] {
    return [cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)];
  }

  const fairVal = useMemo(() => bsPrice(S, K, T, r, q, atmSigma, type), [S, K, T, r, q, atmSigma, type]);

  const curves = useMemo(() => {
    function _strikeToAngle(strike: number): number {
      const norm = (strike - kMin) / (kMax - kMin);
      return -Math.PI / 2 + (norm - 0.5) * Math.PI * 1.5;
    }
    function _ivToR(iv: number): number {
      return maxR * Math.max(0, Math.min(1, (iv - ivMin) / (ivMax - ivMin)));
    }
    function _polarToXY(angle: number, radius: number): [number, number] {
      return [cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)];
    }
    return expiries.map(e => {
      return strikes.map(strike => {
        const iv = bsSynthIV(S, strike, e.T, atmSigma);
        const angle = _strikeToAngle(strike);
        const radius = _ivToR(iv);
        return _polarToXY(angle, radius);
      });
    });
  }, [S, atmSigma, expiries, strikes, kMin, kMax, maxR, ivMin, ivMax, cx, cy]);

  function curvePath(pts: [number, number][]): string {
    return pts.map(([x, y], i) => `${i === 0 ? 'M' : 'L'} ${x.toFixed(1)} ${y.toFixed(1)}`).join(' ');
  }

  const selCurve = curves[selectedExpiryIdx];
  const kAngle = strikeToAngle(K);
  const kIv = bsSynthIV(S, K, T, atmSigma);
  const kR = ivToR(kIv);
  const [dotX, dotY] = polarToXY(kAngle, kR);

  const atmAngle = -Math.PI / 2;

  const eyeR = 28;
  const legendColors = [
    'var(--fg-4)', 'var(--fg-3)', 'var(--fg-2)', 'var(--fg-2)', 'var(--brass)', 'var(--brass-bright)'
  ];

  return (
    <div className="opt-surface">
      <div className="head">
        <h3>Vol Surface <em>polar</em></h3>
      </div>
      <div className="opt-polar-wrap">
        <svg
          viewBox={`0 0 ${SIZE} ${SIZE}`}
          width="100%"
          height={SIZE}
          className="opt-polar"
          style={{ display: 'block' }}
        >
          {ivRings.map(iv => {
            const r = ivToR(iv);
            return (
              <g key={iv}>
                <circle cx={cx} cy={cy} r={r} className={iv === Math.max(...ivRings) ? 'ring outer' : 'ring'} />
                <text x={cx + 4} y={cy - r + 4} className="iv">{(iv * 100).toFixed(0)}%</text>
              </g>
            );
          })}
          {strikes.map((strike, i) => {
            const angle = strikeToAngle(strike);
            const [x1, y1] = polarToXY(angle, 0);
            const [x2, y2] = polarToXY(angle, maxR);
            const isAtm = Math.abs(strike - S) < (kMax - kMin) / (nSpokes * 2);
            return (
              <g key={i}>
                <line
                  x1={x1.toFixed(1)} y1={y1.toFixed(1)}
                  x2={x2.toFixed(1)} y2={y2.toFixed(1)}
                  className={isAtm ? 'spoke atm' : 'spoke'}
                />
                <text
                  x={(cx + (maxR + 14) * Math.cos(angle)).toFixed(1)}
                  y={(cy + (maxR + 14) * Math.sin(angle)).toFixed(1)}
                  textAnchor="middle"
                  dominantBaseline="middle"
                  className={isAtm ? 'tick atm' : 'tick'}
                  fontSize="9"
                >
                  {strike.toFixed(0)}
                </text>
              </g>
            );
          })}
          {curves.map((pts, idx) => {
            const isSel = idx === selectedExpiryIdx;
            if (isSel) return null;
            const color = legendColors[Math.min(idx, legendColors.length - 1)];
            return (
              <path
                key={idx}
                d={curvePath(pts)}
                className="expiry"
                stroke={color}
                strokeWidth="1"
                opacity="0.5"
              />
            );
          })}
          {selCurve && (
            <path
              d={curvePath(selCurve)}
              className="expiry"
              stroke="var(--brass-bright)"
              strokeWidth="2"
              fill="none"
            />
          )}
          <circle cx={dotX.toFixed(1)} cy={dotY.toFixed(1)} r={5} className="dot" />
          <line
            x1={(cx + eyeR * Math.cos(atmAngle)).toFixed(1)}
            y1={(cy + eyeR * Math.sin(atmAngle)).toFixed(1)}
            x2={(cx + (maxR + 2) * Math.cos(atmAngle)).toFixed(1)}
            y2={(cy + (maxR + 2) * Math.sin(atmAngle)).toFixed(1)}
            className="spoke atm"
          />
          <circle cx={cx} cy={cy} r={eyeR} className="eye" />
          <text x={cx} y={cy - 8} textAnchor="middle" className="eye-lbl">{type === 'C' ? 'Call' : 'Put'}</text>
          <text x={cx} y={cy + 10} textAnchor="middle" className="eye-num">${fairVal.toFixed(2)}</text>
        </svg>
      </div>
      <div className="opt-surface-legend">
        {expiries.map((e, idx) => {
          const color = legendColors[Math.min(idx, legendColors.length - 1)];
          const isSel = idx === selectedExpiryIdx;
          return (
            <div key={e.label} className={`item${isSel ? '' : ' muted'}`}>
              <div className="swatch" style={{ background: isSel ? 'var(--brass-bright)' : color }} />
              {e.label}
            </div>
          );
        })}
      </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 => (
              <span key={K} className={K === atmK ? 'atm' : ''}>{K}</span>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}
