// StrikeSimple — a payoff chart (window.PayoffChart), drawn under each primitive's diagram in the
// Product section. A schematic, not data: the strategy's profit or loss against the underlying's
// price, in arbitrary units — at expiry (the solid line) and today, the day it's opened with the
// price at 50 (the dashed line) — with its strikes marked S0 / S1 as the diagrams name them, the
// zero line, the expiry payoff's profit side washed green and its loss side red, and its breakeven
// dotted; captioned under it with `text.title` and a key to the two lines. The drawing is as wide
// as its box (340px at least, the phone layout), so its text stays the same size at any width.
// Styles: `.lp-payoff*` in landing.css.
//
//   kind     "call" | "put" | "bull-spread" | "bear-spread" | "covered-call" | "cash-secured-put"
//   text     content.js → blueprint.payoff: the chart's caption and labels, and each kind's name
//            and description, which screen readers get instead of the picture
(function () {
  // Prices run 0–100 and P&L is in the same units; the P&L window is shared by every kind, so
  // switching between them compares like with like. Lines that run past it (unbounded gains or
  // losses) are clipped at the plot's edge.
  const P_MIN = -22, P_MAX = 24;
  // Each kind is opened with the price at S_NOW, and priced with Black-Scholes (no interest),
  // VOL being σ√T for the time left: 0.4 puts an at-the-money option at about 8 (16% of the
  // price). What it costs then sets both lines: at expiry it's worth its legs' intrinsic value,
  // today their option value — so today's line crosses zero at S_NOW, where it was just bought.
  const S_NOW = 50, VOL = 0.4;
  // legs: [quantity, "call" | "put" | "asset", strike]; cash adds nothing to the P&L.
  const KINDS = {
    call: { strikes: [["0", 50]], legs: [[1, "call", 50]] },
    put: { strikes: [["0", 50]], legs: [[1, "put", 50]] },
    "bull-spread": { strikes: [["0", 38], ["1", 64]], legs: [[1, "call", 38], [-1, "call", 64]] },
    "bear-spread": { strikes: [["1", 36], ["0", 62]], legs: [[1, "put", 62], [-1, "put", 36]] },
    "covered-call": { strikes: [["0", 60]], legs: [[1, "asset"], [-1, "call", 60]] },
    "cash-secured-put": { strikes: [["0", 46]], legs: [[-1, "put", 46]] },
  };
  // The standard normal CDF (Abramowitz & Stegun 7.1.26, to about 1e-7).
  const cdf = (z) => {
    const t = 1 / (1 + 0.3275911 * Math.abs(z) / Math.SQRT2);
    const e = t * (0.254829592 + t * (-0.284496736 + t * (1.421413741 + t * (-1.453152027 + t * 1.061405429)))) * Math.exp(-z * z / 2);
    return z < 0 ? e / 2 : 1 - e / 2;
  };
  // One leg's value at price s with v = σ√T left (v = 0: at expiry).
  const leg = ([q, type, k], s, v) => {
    if (type === "asset") return q * s;
    let call;
    if (v <= 0 || s <= 0) call = Math.max(s - k, 0);
    else {
      const d1 = (Math.log(s / k) + (v * v) / 2) / v;
      call = s * cdf(d1) - k * cdf(d1 - v);
    }
    return q * (type === "call" ? call : call - s + k); // put by parity
  };
  const value = (legs, s, v) => legs.reduce((a, l) => a + leg(l, s, v), 0);

  function PayoffChart({ kind, text }) {
    const k = KINDS[kind];
    const uid = React.useId().replace(/:/g, "");
    const ref = React.useRef(null);
    const [W, setW] = React.useState(640);
    React.useLayoutEffect(() => {
      const el = ref.current;
      if (!el) return;
      const fit = () => setW(Math.round(Math.min(800, Math.max(340, el.clientWidth))));
      fit();
      if (!("ResizeObserver" in window)) return;
      const ro = new ResizeObserver(fit);
      ro.observe(el);
      return () => ro.disconnect();
    }, []);
    if (!k) return null;
    const cost = value(k.legs, S_NOW, VOL);
    const expiry = (s) => value(k.legs, s, 0) - cost;
    const today = (s) => value(k.legs, s, VOL) - cost;
    const H = W < 460 ? 190 : 230;
    const L = 50, R = 8, T = 12, B = 32; // the plot's margins: profit / loss, strike labels
    const pw = W - L - R, ph = H - T - B;
    const x = (s) => L + (s / 100) * pw;
    const y = (p) => T + ((P_MAX - p) / (P_MAX - P_MIN)) * ph;
    const y0 = y(0);
    // The payoff is straight between its strikes, so they and the ends are all the points it needs.
    const xs = [0, ...k.strikes.map((s) => s[1]), 100].sort((a, b) => a - b);
    const pts = xs.map((s) => [s, expiry(s)]);
    const path = (ps) => ps.map(([s, p], i) => `${i ? "L" : "M"}${x(s).toFixed(1)},${y(p).toFixed(1)}`).join(" ");
    const line = path(pts);
    // Today's is a curve: sampled every half a price unit (its far ends run off the plot, clipped).
    const now = path(Array.from({ length: 201 }, (_, i) => [i / 2, today(i / 2)]));
    const area = `${line} L${x(100).toFixed(1)},${y0.toFixed(1)} L${x(0).toFixed(1)},${y0.toFixed(1)} Z`;
    // Breakevens: where the expiry line crosses zero, with the side it rises toward. The label goes
    // under the zero line on that side, where the expiry line never is — unless today's curve runs
    // through that spot (it does where the position is short an option: Anchor), then over the
    // zero line on the other side, where neither line is.
    const evens = [];
    for (let i = 1; i < pts.length; i++) {
      const [s1, p1] = pts[i - 1], [s2, p2] = pts[i];
      if ((p1 < 0 && p2 > 0) || (p1 > 0 && p2 < 0)) evens.push({ s: s1 + ((0 - p1) / (p2 - p1)) * (s2 - s1), up: p2 > p1 });
    }
    const crosses = (x1, x2, top, bottom) => {
      for (let px = x1; px <= x2; px += 2) {
        const py = y(today(((px - L) / pw) * 100));
        if (py >= top && py <= bottom) return true;
      }
      return false;
    };
    const evenLabel = (e) => {
      const at = x(e.s), w = text.breakeven.length * 6.6; // the label's rough width at 12px
      const spots = [{ side: e.up ? 1 : -1, under: true }, { side: e.up ? -1 : 1, under: false }];
      const free = ({ side, under }) => {
        const x1 = side > 0 ? at + 8 : at - 8 - w, top = under ? y0 + 2 : y0 - 24;
        return !crosses(x1 - 4, x1 + w + 4, top, top + 22); // with a little room around it
      };
      const { side, under } = spots.find(free) || spots[0];
      return { x: at + side * 8, y: under ? y0 + 18 : y0 - 8, anchor: side > 0 ? "start" : "end" };
    };
    const id = (n) => `pay-${uid}-${n}`;
    return (
      <figure ref={ref} className="lp-payoff">
        <svg viewBox={`0 0 ${W} ${H}`} role="img" aria-label={`${text.names[kind]}: ${text.descriptions[kind]} ${text.todayNote}`}>
          <defs>
            <clipPath id={id("plot")}><rect x={L} y={T} width={pw} height={ph} /></clipPath>
            <clipPath id={id("up")}><rect x={L} y={T} width={pw} height={y0 - T} /></clipPath>
            <clipPath id={id("down")}><rect x={L} y={y0} width={pw} height={T + ph - y0} /></clipPath>
          </defs>
          {/* strikes: a faint rule across the plot, named under the axis */}
          {k.strikes.map(([n, s]) => (
            <g key={n}>
              <line className="lp-payoff-strike" x1={x(s)} x2={x(s)} y1={T} y2={T + ph} />
              <text className="lp-payoff-label" x={x(s)} y={T + ph + 18} textAnchor="middle">S<tspan className="lp-payoff-sub" dy="3">{n}</tspan></text>
            </g>
          ))}
          <line className="lp-payoff-axis" x1={L} x2={L + pw} y1={T + ph} y2={T + ph} />
          <text className="lp-payoff-label" x={L + pw} y={T + ph + 18} textAnchor="end">{text.price}</text>
          <line className="lp-payoff-zero" x1={L} x2={L + pw} y1={y0} y2={y0} />
          <text className="lp-payoff-label" x={L - 8} y={y0 - 6} textAnchor="end">{text.profit}</text>
          <text className="lp-payoff-label" x={L - 8} y={y0 + 15} textAnchor="end">{text.loss}</text>
          <g clipPath={`url(#${id("plot")})`}>
            <path className="lp-payoff-wash lp-payoff-wash--up" d={area} clipPath={`url(#${id("up")})`} />
            <path className="lp-payoff-wash lp-payoff-wash--down" d={area} clipPath={`url(#${id("down")})`} />
            <path className="lp-payoff-now" d={now} />
            <path className="lp-payoff-line" d={line} pathLength="1" />
          </g>
          {evens.map((e) => {
            const t = evenLabel(e);
            return (
              <g key={e.s} className="lp-payoff-even">
                <circle cx={x(e.s)} cy={y0} r="4" />
                <text className="lp-payoff-label" x={t.x} y={t.y} textAnchor={t.anchor}>{text.breakeven}</text>
              </g>
            );
          })}
        </svg>
        {/* the caption, then the key to the lines (the picture's own; screen readers have the label) */}
        <figcaption className="lp-payoff-cap">
          <span className="lp-strat-caption">{text.title}</span>
          <span className="lp-payoff-key" aria-hidden="true">
            <span className="lp-payoff-key-item"><span className="lp-payoff-swatch" />{text.expiry}</span>
            <span className="lp-payoff-key-item"><span className="lp-payoff-swatch lp-payoff-swatch--now" />{text.today}</span>
          </span>
        </figcaption>
      </figure>
    );
  }

  window.PayoffChart = PayoffChart;
})();
