/* math6_svg.js — SVG-хелперы учебника «Математика 6». window.Math6.
 * Самодостаточно (без зависимостей). Все функции возвращают строку SVG,
 * готовую к вставке в innerHTML. Координаты SVG: y растёт вниз — учтено.
 *
 * Готово (Phase 0 / Глава 1): fmt, box, numberLine (прямая/луч с метками и точками),
 *   plane (декартова плоскость — фундамент для Главы 5).
 * Будет добавлено при наполнении глав 5–6: plotFn, circleFig, triangleFig, solid, net,
 *   reflectPoint/reflectLine (симметрия).
 */
(function () {
'use strict';
if (window.Math6 && window.Math6.__installed) return;
var M = window.Math6 = window.Math6 || {};
M.__installed = true;

/* Русская запись числа: десятичная запятая, без хвостовых нулей */
M.fmt = function (n) {
  if (n == null || !isFinite(n)) return '' + n;
  var s = (Math.round(n * 1e9) / 1e9).toString();
  return s.replace('.', ',');
};
function esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); }

/* Обёртка <svg> с фоном */
M.box = function (w, h, inner, opts) {
  opts = opts || {};
  return '<div class="m6-fig" style="max-width:' + (opts.maxw || w) + 'px">'
    + '<svg viewBox="0 0 ' + w + ' ' + h + '" preserveAspectRatio="xMidYMid meet" '
    + 'style="width:100%;height:auto;display:block;background:' + (opts.bg || 'var(--card,#fff)') + ';border-radius:10px;border:1px solid var(--border,#e2e8f0)">'
    + (inner || '') + '</svg></div>';
};

/* === ЧИСЛОВАЯ ПРЯМАЯ / КООРДИНАТНЫЙ ЛУЧ ===
 * opts: {min,max, minor, major, ray(bool), marks:[{v,label,color,open,above}],
 *        segments:[{from,to,color}], width,height, title}
 */
M.numberLine = function (opts) {
  opts = opts || {};
  var min = opts.min != null ? opts.min : 0;
  var max = opts.max != null ? opts.max : 10;
  var minor = opts.minor || 1;
  var major = opts.major || minor;
  var W = opts.width || 540, H = opts.height || 92;
  var pad = 34;
  var axisY = Math.round(H * 0.58);
  var x0 = pad, x1 = W - pad;
  function X(v) { return x0 + (v - min) / (max - min) * (x1 - x0); }
  var col = opts.color || 'var(--pri,#4f46e5)';
  var s = '';

  /* выделенные отрезки/интервалы (рисуем под осью) */
  (opts.segments || []).forEach(function (seg) {
    var a = X(seg.from), b = X(seg.to);
    s += '<line x1="' + a + '" y1="' + axisY + '" x2="' + b + '" y2="' + axisY + '" stroke="' + (seg.color || '#10b981') + '" stroke-width="6" stroke-linecap="round" opacity="0.5"/>';
  });

  /* ось со стрелками */
  s += '<line x1="' + (x0 - 8) + '" y1="' + axisY + '" x2="' + (x1 + 8) + '" y2="' + axisY + '" stroke="' + col + '" stroke-width="2"/>';
  s += '<polygon points="' + (x1 + 8) + ',' + axisY + ' ' + (x1 - 2) + ',' + (axisY - 5) + ' ' + (x1 - 2) + ',' + (axisY + 5) + '" fill="' + col + '"/>';
  if (!opts.ray) s += '<polygon points="' + (x0 - 8) + ',' + axisY + ' ' + (x0 + 2) + ',' + (axisY - 5) + ' ' + (x0 + 2) + ',' + (axisY + 5) + '" fill="' + col + '"/>';

  /* деления и подписи */
  var nMinor = Math.round((max - min) / minor);
  for (var i = 0; i <= nMinor; i++) {
    var v = min + i * minor; v = Math.round(v * 1e6) / 1e6;
    var x = X(v);
    var isMajor = Math.abs(Math.round((v - min) / major) - (v - min) / major) < 1e-6;
    var len = isMajor ? 9 : 5;
    s += '<line x1="' + x + '" y1="' + (axisY - len) + '" x2="' + x + '" y2="' + (axisY + len) + '" stroke="' + col + '" stroke-width="' + (isMajor ? 1.6 : 1) + '"/>';
    if (isMajor && opts.labels !== false) {
      s += '<text x="' + x + '" y="' + (axisY + 24) + '" text-anchor="middle" font-size="12" font-family="JetBrains Mono,monospace" fill="var(--muted,#64748b)">' + esc(M.fmt(v)) + '</text>';
    }
  }

  /* точки-маркеры */
  (opts.marks || []).forEach(function (mk) {
    var x = X(mk.v); var c = mk.color || '#e11d48';
    if (mk.open) s += '<circle cx="' + x + '" cy="' + axisY + '" r="6" fill="var(--card,#fff)" stroke="' + c + '" stroke-width="2.5"/>';
    else s += '<circle cx="' + x + '" cy="' + axisY + '" r="6" fill="' + c + '" stroke="#fff" stroke-width="1.5"/>';
    if (mk.label) {
      var ly = mk.above === false ? axisY + 38 : axisY - 14;
      s += '<text x="' + x + '" y="' + ly + '" text-anchor="middle" font-size="13" font-family="Unbounded,Inter,sans-serif" font-weight="800" fill="' + c + '">' + esc(mk.label) + '</text>';
    }
  });

  return M.box(W, H, s, { maxw: opts.maxw || W, bg: opts.bg });
};

/* === ДЕКАРТОВА ПЛОСКОСТЬ (фундамент для Главы 5) ===
 * opts: {xmin,xmax,ymin,ymax, points:[{x,y,label,color,open}],
 *        segments:[{from:{x,y},to:{x,y},color,dash}], quadrants(bool),
 *        plot:{fn,color,samples,from,to}, size, unitLabels(bool)}
 */
M.plane = function (opts) {
  opts = opts || {};
  var xmin = opts.xmin != null ? opts.xmin : -5, xmax = opts.xmax != null ? opts.xmax : 5;
  var ymin = opts.ymin != null ? opts.ymin : -5, ymax = opts.ymax != null ? opts.ymax : 5;
  var S = opts.size || 360, pad = 22;
  function X(x) { return pad + (x - xmin) / (xmax - xmin) * (S - 2 * pad); }
  function Y(y) { return S - pad - (y - ymin) / (ymax - ymin) * (S - 2 * pad); }
  var axc = 'var(--text,#0f172a)';
  var s = '';

  if (opts.quadrants) {
    var cx = X(0), cy = Y(0);
    s += '<rect x="' + cx + '" y="' + pad + '" width="' + (S - pad - cx) + '" height="' + (cy - pad) + '" fill="rgba(79,70,229,.05)"/>';
    s += '<rect x="' + pad + '" y="' + cy + '" width="' + (cx - pad) + '" height="' + (S - pad - cy) + '" fill="rgba(225,29,72,.05)"/>';
  }
  /* сетка */
  for (var gx = Math.ceil(xmin); gx <= Math.floor(xmax); gx++) {
    s += '<line x1="' + X(gx) + '" y1="' + pad + '" x2="' + X(gx) + '" y2="' + (S - pad) + '" stroke="var(--border,#e2e8f0)" stroke-width="' + (gx === 0 ? 0 : 0.8) + '"/>';
  }
  for (var gy = Math.ceil(ymin); gy <= Math.floor(ymax); gy++) {
    s += '<line x1="' + pad + '" y1="' + Y(gy) + '" x2="' + (S - pad) + '" y2="' + Y(gy) + '" stroke="var(--border,#e2e8f0)" stroke-width="' + (gy === 0 ? 0 : 0.8) + '"/>';
  }
  /* оси */
  s += '<line x1="' + pad + '" y1="' + Y(0) + '" x2="' + (S - pad + 6) + '" y2="' + Y(0) + '" stroke="' + axc + '" stroke-width="1.6"/>';
  s += '<polygon points="' + (S - pad + 6) + ',' + Y(0) + ' ' + (S - pad - 2) + ',' + (Y(0) - 4) + ' ' + (S - pad - 2) + ',' + (Y(0) + 4) + '" fill="' + axc + '"/>';
  s += '<line x1="' + X(0) + '" y1="' + (S - pad) + '" x2="' + X(0) + '" y2="' + (pad - 6) + '" stroke="' + axc + '" stroke-width="1.6"/>';
  s += '<polygon points="' + X(0) + ',' + (pad - 6) + ' ' + (X(0) - 4) + ',' + (pad + 2) + ' ' + (X(0) + 4) + ',' + (pad + 2) + '" fill="' + axc + '"/>';
  s += '<text x="' + (S - pad + 2) + '" y="' + (Y(0) + 16) + '" font-size="13" font-style="italic" font-family="serif" fill="' + axc + '">x</text>';
  s += '<text x="' + (X(0) + 8) + '" y="' + (pad + 2) + '" font-size="13" font-style="italic" font-family="serif" fill="' + axc + '">y</text>';
  s += '<text x="' + (X(0) - 12) + '" y="' + (Y(0) + 16) + '" font-size="11" font-family="JetBrains Mono,monospace" fill="var(--muted,#64748b)">0</text>';

  /* график функции */
  if (opts.plot && typeof opts.plot.fn === 'function') {
    var pl = opts.plot, from = pl.from != null ? pl.from : xmin, to = pl.to != null ? pl.to : xmax;
    var N = pl.samples || 120, pts = [], started = false, d = '';
    for (var k = 0; k <= N; k++) {
      var xv = from + (to - from) * k / N, yv = pl.fn(xv);
      if (yv == null || !isFinite(yv) || yv < ymin - 1 || yv > ymax + 1) { started = false; continue; }
      d += (started ? ' L ' : ' M ') + X(xv) + ' ' + Y(yv); started = true;
    }
    s += '<path d="' + d + '" fill="none" stroke="' + (pl.color || 'var(--pri,#4f46e5)') + '" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>';
  }
  /* ломаная (график реального процесса по точкам) */
  if (opts.polyline && opts.polyline.length) {
    var pl2 = opts.polyline, pts2 = pl2.map(function (p) { return X(p.x) + ',' + Y(p.y); }).join(' ');
    s += '<polyline points="' + pts2 + '" fill="none" stroke="' + (opts.polylineColor || 'var(--pri,#4f46e5)') + '" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>';
    if (opts.polylineDots) pl2.forEach(function (p) { s += '<circle cx="' + X(p.x) + '" cy="' + Y(p.y) + '" r="3.5" fill="' + (opts.polylineColor || 'var(--pri,#4f46e5)') + '"/>'; });
  }
  /* отрезки */
  (opts.segments || []).forEach(function (sg) {
    s += '<line x1="' + X(sg.from.x) + '" y1="' + Y(sg.from.y) + '" x2="' + X(sg.to.x) + '" y2="' + Y(sg.to.y) + '" stroke="' + (sg.color || 'var(--pri,#4f46e5)') + '" stroke-width="2"' + (sg.dash ? ' stroke-dasharray="' + sg.dash + '"' : '') + '/>';
  });
  /* точки */
  (opts.points || []).forEach(function (p) {
    var c = p.color || '#e11d48';
    if (p.open) s += '<circle cx="' + X(p.x) + '" cy="' + Y(p.y) + '" r="5" fill="var(--card,#fff)" stroke="' + c + '" stroke-width="2.5"/>';
    else s += '<circle cx="' + X(p.x) + '" cy="' + Y(p.y) + '" r="5" fill="' + c + '" stroke="#fff" stroke-width="1.5"/>';
    if (p.label) s += '<text x="' + (X(p.x) + 8) + '" y="' + (Y(p.y) - 7) + '" font-size="12" font-family="Unbounded,Inter,sans-serif" font-weight="700" fill="' + c + '">' + esc(p.label) + '</text>';
  });
  return M.box(S, S, s, { maxw: opts.maxw || S, bg: opts.bg });
};

/* === КРУГОВАЯ ДИАГРАММА ===
 * segs: [{value,label,color}]. opts: {size, r}. Возвращает boxed SVG (проценты в секторах).
 */
M.pie = function (segs, opts) {
  opts = opts || {};
  var S = opts.size || 220, cx = S / 2, cy = S / 2, r = opts.r || (S / 2 - 8);
  var total = segs.reduce(function (a, s) { return a + s.value; }, 0) || 1;
  var palette = ['#4f46e5', '#0891b2', '#e11d48', '#059669', '#d97706', '#7c3aed', '#db2777'];
  var ang = -Math.PI / 2, s = '';
  segs.forEach(function (seg, i) {
    var frac = seg.value / total, a2 = ang + frac * 2 * Math.PI;
    var col = seg.color || palette[i % palette.length];
    if (frac >= 0.999) { s += '<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="' + col + '"/>'; }
    else {
      var x1 = cx + r * Math.cos(ang), y1 = cy + r * Math.sin(ang), x2 = cx + r * Math.cos(a2), y2 = cy + r * Math.sin(a2), large = frac > 0.5 ? 1 : 0;
      s += '<path d="M ' + cx + ' ' + cy + ' L ' + x1 + ' ' + y1 + ' A ' + r + ' ' + r + ' 0 ' + large + ' 1 ' + x2 + ' ' + y2 + ' Z" fill="' + col + '" stroke="var(--card,#fff)" stroke-width="1.5"/>';
    }
    var mid = ang + frac * Math.PI, lx = cx + r * 0.62 * Math.cos(mid), ly = cy + r * 0.62 * Math.sin(mid);
    if (frac > 0.05) s += '<text x="' + lx + '" y="' + (ly + 4) + '" text-anchor="middle" font-size="12" font-weight="700" fill="#fff">' + Math.round(frac * 100) + '%</text>';
    ang = a2;
  });
  return M.box(S, S, s, { maxw: opts.maxw || S });
};

/* === КРУГИ ЭЙЛЕРА / ДИАГРАММА ВЕННА (два множества) ===
 * opts: {a,b (подписи), shade:'inter'|'union'|'a'|'b'|'none', shadeColor,
 *        regions:{aOnly,inter,bOnly,outside}} — числа/текст в областях.
 */
M.venn = function (opts) {
  opts = opts || {};
  var W = 300, H = 190, cA = { x: 115, y: 100 }, cB = { x: 185, y: 100 }, r = 66;
  var sc = opts.shadeColor || '#7c3aed';
  var s = '<defs><clipPath id="m6vA"><circle cx="' + cA.x + '" cy="' + cA.y + '" r="' + r + '"/></clipPath></defs>';
  var cir = function (c, fill, op) { return '<circle cx="' + c.x + '" cy="' + c.y + '" r="' + r + '" fill="' + fill + '"' + (op != null ? ' opacity="' + op + '"' : '') + '/>'; };
  if (opts.shade === 'union') { s += cir(cA, sc, 0.22) + cir(cB, sc, 0.22); }
  else if (opts.shade === 'inter') { s += '<g clip-path="url(#m6vA)">' + cir(cB, sc, 0.4) + '</g>'; }
  else if (opts.shade === 'a') { s += cir(cA, sc, 0.3) + '<g clip-path="url(#m6vA)">' + cir(cB, 'var(--card,#fff)', 1) + '</g>'; }
  else if (opts.shade === 'b') { s += cir(cB, sc, 0.3) + '<g clip-path="url(#m6vA)">' + cir(cB, 'var(--card,#fff)', 1) + '</g>' + '<g clip-path="url(#m6vA)">' + cir(cB, sc, 0.3) + '</g>'; }
  /* контуры */
  s += '<circle cx="' + cA.x + '" cy="' + cA.y + '" r="' + r + '" fill="none" stroke="#4f46e5" stroke-width="2.5"/>';
  s += '<circle cx="' + cB.x + '" cy="' + cB.y + '" r="' + r + '" fill="none" stroke="#e11d48" stroke-width="2.5"/>';
  /* подписи множеств */
  s += '<text x="' + (cA.x - 40) + '" y="' + (cA.y - r + 4) + '" font-size="16" font-weight="800" font-family="Unbounded,Inter,sans-serif" fill="#4f46e5">' + (opts.a || 'A') + '</text>';
  s += '<text x="' + (cB.x + 30) + '" y="' + (cB.y - r + 4) + '" font-size="16" font-weight="800" font-family="Unbounded,Inter,sans-serif" fill="#e11d48">' + (opts.b || 'B') + '</text>';
  /* числа/текст в областях */
  var rg = opts.regions;
  if (rg) {
    function lab(x, y, t, col) { if (t == null || t === '') return ''; return '<text x="' + x + '" y="' + (y + 5) + '" text-anchor="middle" font-size="15" font-weight="700" font-family="JetBrains Mono,monospace" fill="' + (col || 'var(--text,#0f172a)') + '">' + t + '</text>'; }
    s += lab(cA.x - 34, cA.y, rg.aOnly);
    s += lab((cA.x + cB.x) / 2, cA.y, rg.inter);
    s += lab(cB.x + 34, cB.y, rg.bOnly);
    if (rg.outside != null) s += lab(W - 22, H - 14, rg.outside, 'var(--muted,#64748b)');
  }
  return M.box(W, H, s, { maxw: opts.maxw || W });
};

})();
