/* eslint-disable no-undef */
// =====================================================
// Blow-up viz: y' = y^2 — counterexample to global existence
// Default: y(0)=1 -> blows at x=1; y(0)=-1 -> blows at x=-1; y=0 trivial
// =====================================================

function BlowUpViz() {
  const [y0a, setY0a] = useState(1);
  const [y0b, setY0b] = useState(-1);
  const [showTrivial, setShowTrivial] = useState(true);
  const [showAsym, setShowAsym] = useState(true);

  // exact: y(x) = y0 / (1 - y0 * (x - x0)), blow-up at x = x0 + 1/y0
  const exact = (y0) => (x) => {
    if (Math.abs(y0) < 1e-9) return 0;
    const denom = 1 - y0 * x; // x0 = 0
    return y0 / denom;
  };

  const blowUpA = useMemo(() => Math.abs(y0a) > 1e-9 ? 1 / y0a : null, [y0a]);
  const blowUpB = useMemo(() => Math.abs(y0b) > 1e-9 ? 1 / y0b : null, [y0b]);

  const canvasRef = useCanvas((ctx, W, H) => {
    const T = makeTransform({ xMin: -3, xMax: 3, yMin: -6, yMax: 6, W, H, pad: 38 });
    drawAxes(ctx, T, { tickStep: 1, xLabel: 'x', yLabel: 'y' });

    // vertical asymptote lines
    if (showAsym && blowUpA !== null && blowUpA > T.xMin && blowUpA < T.xMax) {
      ctx.save();
      ctx.strokeStyle = 'rgba(184,88,31,0.55)';
      ctx.setLineDash([5, 4]);
      ctx.lineWidth = 1.5;
      ctx.beginPath();
      ctx.moveTo(T.X(blowUpA), T.Y(T.yMin));
      ctx.lineTo(T.X(blowUpA), T.Y(T.yMax));
      ctx.stroke();
      ctx.restore();
    }
    if (showAsym && blowUpB !== null && blowUpB > T.xMin && blowUpB < T.xMax) {
      ctx.save();
      ctx.strokeStyle = 'rgba(184,88,31,0.55)';
      ctx.setLineDash([5, 4]);
      ctx.lineWidth = 1.5;
      ctx.beginPath();
      ctx.moveTo(T.X(blowUpB), T.Y(T.yMin));
      ctx.lineTo(T.X(blowUpB), T.Y(T.yMax));
      ctx.stroke();
      ctx.restore();
    }

    // draw curves piecewise around asymptotes
    const drawCurve = (y0, color) => {
      if (Math.abs(y0) < 1e-9) return;
      const blowAt = 1 / y0;
      const fn = exact(y0);
      const samples = 400;
      // Two branches: (-inf, blowAt) and (blowAt, +inf)
      const branches = [];
      if (blowAt > T.xMin) branches.push([Math.max(T.xMin - 0.5, blowAt - 6), blowAt - 0.005]);
      else                 branches.push([T.xMin - 0.5, T.xMax + 0.5]);
      if (blowAt < T.xMax) branches.push([blowAt + 0.005, T.xMax + 0.5]);

      for (const [a, b] of branches) {
        if (a >= b) continue;
        const pts = [];
        for (let i = 0; i <= samples; i++) {
          const x = a + (i / samples) * (b - a);
          const y = fn(x);
          if (!isFinite(y)) continue;
          pts.push([x, y]);
        }
        drawPath(ctx, T, pts, { color, lineWidth: 2.6 });
      }
    };

    drawCurve(y0a, '#2a5e9e');
    drawCurve(y0b, '#a8392c');
    if (showTrivial) {
      drawPath(ctx, T, [[T.xMin, 0], [T.xMax, 0]], { color: '#1f8a76', lineWidth: 2.4 });
    }

    // initial point dots
    drawDot(ctx, T, 0, y0a, { color: '#2a5e9e', stroke: '#fbf6e9', r: 4.5 });
    drawDot(ctx, T, 0, y0b, { color: '#a8392c', stroke: '#fbf6e9', r: 4.5 });

  }, [y0a, y0b, showTrivial, showAsym, blowUpA, blowUpB]);

  return (
    <VizWrap
      title="Контрпример к глобальной разрешимости:"
      formula="y′ = y²"
      captionUnder="Локальная единственность Пикара есть, но решение y(x) = y₀/(1−y₀·x) взрывается за конечное время x = 1/y₀."
      controls={
        <React.Fragment>
          <h4>Начальные условия</h4>
          <Slider label="y(0) — синяя" value={y0a} setValue={setY0a} min={-3} max={3} step={0.05} />
          <Slider label="y(0) — красная" value={y0b} setValue={setY0b} min={-3} max={3} step={0.05} />
          <h4>Отображение</h4>
          <Toggle label="Тривиальное y≡0" value={showTrivial} setValue={setShowTrivial} />
          <Toggle label="Линии взрыва" value={showAsym} setValue={setShowAsym} />
          <h4>Точки взрыва</h4>
          <div className="ctl-legend">
            <div className="ctl-legend-row">
              <span className="ctl-legend-swatch" style={{ background: '#2a5e9e' }}></span>
              <span>{blowUpA !== null ? `x* = ${blowUpA.toFixed(3)}` : 'не взрывается'}</span>
            </div>
            <div className="ctl-legend-row">
              <span className="ctl-legend-swatch" style={{ background: '#a8392c' }}></span>
              <span>{blowUpB !== null ? `x* = ${blowUpB.toFixed(3)}` : 'не взрывается'}</span>
            </div>
            {showTrivial ? (
              <div className="ctl-legend-row">
                <span className="ctl-legend-swatch" style={{ background: '#1f8a76' }}></span>
                <span>y ≡ 0 — тривиальное</span>
              </div>
            ) : null}
          </div>
          <div className="ctl-note">Уход в бесконечность за конечное время — альтернатива 2 теоремы о продолжении решения.</div>
        </React.Fragment>
      }
    >
      <canvas ref={canvasRef} />
    </VizWrap>
  );
}

window.BlowUpViz = BlowUpViz;
