// ============================================================
// ai-markdown.jsx — Renderer ricco per output AI (REALE, condiviso)
// ============================================================
//
// Sessione 127. Sostituisce i parser "markdown-lite" duplicati (Copilot
// MsgBody + ai-insight AiInsightBody) che gestivano solo **bold** e bullet:
// le tabelle markdown uscivano come testo su una riga (disallineate) e i
// grafici non esistevano.
//
// Supporta: heading (#..######), grassetto/corsivo/codice inline, link
// http(s)/mailto sanitizzati, liste puntate + numerate, citazioni, righe
// orizzontali, blocchi di codice ``` e — soprattutto — TABELLE markdown
// reali (allineate, scrollabili) e GRAFICI via blocco ```chart con JSON.
//
// VINCOLO prototipo: Babel-in-browser → niente `...rest` / `{...spread}` nei
// componenti (corrompe le props su file grandi). Solo props esplicite + loop.
// Stili iniettati una volta (no dipendenza da styles.css → deploy pull-only).

(function ensureAiMdStyles() {
  if (typeof document === 'undefined') return;
  if (document.getElementById('ai-md-styles')) return;
  const style = document.createElement('style');
  style.id = 'ai-md-styles';
  style.textContent = [
    '.ai-md{font-size:12.5px;line-height:1.6;color:var(--text-1);word-break:break-word}',
    '.ai-md>:first-child{margin-top:0}.ai-md>:last-child{margin-bottom:0}',
    '.ai-md p{margin:0 0 8px}',
    '.ai-md h4,.ai-md h5,.ai-md h6{margin:10px 0 6px;line-height:1.3;font-weight:600}',
    '.ai-md h4{font-size:14px}.ai-md h5{font-size:12.5px}.ai-md h6{font-size:11.5px;color:var(--text-2)}',
    '.ai-md ul,.ai-md ol{margin:6px 0;padding-left:20px}.ai-md li{margin:2px 0}',
    '.ai-md a{color:var(--accent-2,var(--accent));text-decoration:underline}',
    '.ai-md code.ai-md-code{font-family:var(--font-mono,monospace);font-size:11.5px;background:var(--bg-2);padding:1px 5px;border-radius:4px}',
    '.ai-md pre.ai-md-pre{background:var(--bg-2);border:1px solid var(--line);border-radius:6px;padding:10px 12px;overflow:auto;font-size:11.5px;margin:8px 0}',
    '.ai-md pre.ai-md-pre code{font-family:var(--font-mono,monospace);white-space:pre}',
    '.ai-md blockquote{margin:8px 0;padding:6px 12px;border-left:3px solid var(--accent);background:color-mix(in oklch,var(--accent) 6%,transparent);color:var(--text-2)}',
    '.ai-md hr{border:0;border-top:1px solid var(--line);margin:10px 0}',
    '.ai-md-tablewrap{overflow-x:auto;margin:8px 0;border:1px solid var(--line);border-radius:6px}',
    '.ai-md table{border-collapse:collapse;width:100%;font-size:11.5px}',
    '.ai-md th,.ai-md td{border-bottom:1px solid var(--line);border-right:1px solid var(--line);padding:5px 9px;vertical-align:top;white-space:nowrap}',
    '.ai-md th:last-child,.ai-md td:last-child{border-right:0}.ai-md tbody tr:last-child td{border-bottom:0}',
    '.ai-md thead th{background:var(--bg-2);font-weight:600;position:sticky;top:0}',
    '.ai-md tbody tr:nth-child(even) td{background:color-mix(in oklch,var(--bg-2) 45%,transparent)}',
    '.ai-md-chart{margin:10px 0;padding:10px 12px;border:1px solid var(--line);border-radius:8px;background:var(--bg-1)}',
    '.ai-md-chart .ttl{font-size:11.5px;font-weight:600;color:var(--text-1);margin-bottom:6px}',
    '.ai-md-chart .legend{display:flex;flex-wrap:wrap;gap:12px;margin-top:8px;font-size:10.5px;color:var(--text-2)}',
    '.ai-md-chart .legend i{width:9px;height:9px;border-radius:2px;display:inline-block;margin-right:5px;vertical-align:-1px}',
    '.ai-md-chart text{fill:var(--text-2);font-size:9px;font-family:var(--font-sans,inherit)}',
    '.ai-md-chart .axis{stroke:var(--line)}',
  ].join('');
  document.head.appendChild(style);
})();

// Palette grafici (CSS vars con fallback).
const AI_MD_PALETTE = [
  'var(--accent,#3b82f6)',
  'var(--brand-1,#7c5cff)',
  'var(--ok,#16a34a)',
  'var(--warn,#d97706)',
  'var(--err,#dc2626)',
  'var(--bg-4,#94a3b8)',
];

function aiMdMax(arr) {
  let m = 0;
  for (let i = 0; i < arr.length; i++) { const v = arr[i]; if (Number.isFinite(v) && v > m) m = v; }
  return m;
}

function aiMdFmtNum(n) {
  if (!Number.isFinite(n)) return '';
  const a = Math.abs(n);
  if (a >= 1e9) return (n / 1e9).toFixed(a >= 1e10 ? 0 : 1) + 'B';
  if (a >= 1e6) return (n / 1e6).toFixed(a >= 1e7 ? 0 : 1) + 'M';
  if (a >= 1e3) return (n / 1e3).toFixed(a >= 1e4 ? 0 : 1) + 'k';
  return String(Math.round(n * 100) / 100);
}

function aiMdTrunc(s, n) {
  const str = String(s == null ? '' : s);
  return str.length > n ? str.slice(0, n - 1) + '…' : str;
}

// ---- Inline parsing: `code` | **bold** | *italic* | _italic_ | [text](url) ----
function aiMdInline(text, kp) {
  const s = String(text == null ? '' : text);
  const nodes = [];
  const re = /(`[^`]+`)|(\*\*[^*]+\*\*)|(\*[^*\s][^*]*\*)|(_[^_\s][^_]*_)|(\[[^\]]+\]\([^)\s]+\))/g;
  let last = 0; let m; let k = 0;
  while ((m = re.exec(s)) !== null) {
    if (m.index > last) nodes.push(React.createElement(React.Fragment, { key: kp + 'p' + (k++) }, s.slice(last, m.index)));
    const tok = m[0];
    if (tok.charAt(0) === '`') {
      nodes.push(React.createElement('code', { key: kp + 'c' + (k++), className: 'ai-md-code' }, tok.slice(1, -1)));
    } else if (tok.slice(0, 2) === '**') {
      nodes.push(React.createElement('strong', { key: kp + 'b' + (k++) }, tok.slice(2, -2)));
    } else if (tok.charAt(0) === '*' || tok.charAt(0) === '_') {
      nodes.push(React.createElement('em', { key: kp + 'i' + (k++) }, tok.slice(1, -1)));
    } else {
      const mm = tok.match(/^\[([^\]]+)\]\(([^)\s]+)\)$/);
      const label = mm ? mm[1] : tok;
      const url = mm ? mm[2] : '';
      const safe = /^(https?:|mailto:)/i.test(url);
      if (safe) nodes.push(React.createElement('a', { key: kp + 'a' + (k++), href: url, target: '_blank', rel: 'noopener noreferrer' }, label));
      else nodes.push(React.createElement(React.Fragment, { key: kp + 'a' + (k++) }, label));
    }
    last = m.index + tok.length;
  }
  if (last < s.length) nodes.push(React.createElement(React.Fragment, { key: kp + 'p' + (k++) }, s.slice(last)));
  return nodes;
}

// Testo multiriga dentro un paragrafo → inline + <br/> sui ritorni a capo morbidi.
function aiMdMultiline(text, kp) {
  const parts = String(text == null ? '' : text).split('\n');
  const out = [];
  for (let i = 0; i < parts.length; i++) {
    if (i > 0) out.push(React.createElement('br', { key: kp + 'br' + i }));
    const inl = aiMdInline(parts[i], kp + 'l' + i + '_');
    for (let j = 0; j < inl.length; j++) out.push(inl[j]);
  }
  return out;
}

function aiMdSplitRow(line) {
  let s = line.trim();
  if (s.charAt(0) === '|') s = s.slice(1);
  if (s.charAt(s.length - 1) === '|') s = s.slice(0, -1);
  return s.split('|').map((c) => c.trim());
}

function aiMdAligns(sepLine) {
  return aiMdSplitRow(sepLine).map((c) => {
    const l = c.charAt(0) === ':';
    const r = c.charAt(c.length - 1) === ':';
    if (l && r) return 'center';
    if (r) return 'right';
    if (l) return 'left';
    return 'left';
  });
}

function aiMdIsSpecial(line, next) {
  if (line == null) return false;
  if (/^\s*```/.test(line)) return true;
  if (/^(#{1,6})\s+/.test(line)) return true;
  if (/^\s*([-*_])\1\1+\s*$/.test(line)) return true;
  if (/^\s*>\s?/.test(line)) return true;
  if (/^\s*[-*•]\s+/.test(line)) return true;
  if (/^\s*\d+[.)]\s+/.test(line)) return true;
  if (/\|/.test(line) && next != null && /-/.test(next) && /^\s*\|?[\s:|-]+\|?\s*$/.test(next)) return true;
  return false;
}

// ---- Block parsing ----
function aiMdBlocks(text) {
  const src = String(text == null ? '' : text).replace(/\r\n/g, '\n');
  const lines = src.split('\n');
  const blocks = [];
  let i = 0;
  while (i < lines.length) {
    const line = lines[i];
    // fenced code / chart
    if (/^\s*```/.test(line)) {
      const lang = line.replace(/^\s*```/, '').trim().toLowerCase();
      const buf = [];
      i++;
      while (i < lines.length && !/^\s*```/.test(lines[i])) { buf.push(lines[i]); i++; }
      i++;
      if (lang === 'chart') blocks.push({ type: 'chart', raw: buf.join('\n') });
      else blocks.push({ type: 'code', lang, text: buf.join('\n') });
      continue;
    }
    // table
    if (/\|/.test(line) && i + 1 < lines.length && /-/.test(lines[i + 1]) && /^\s*\|?[\s:|-]+\|?\s*$/.test(lines[i + 1])) {
      const header = aiMdSplitRow(line);
      const aligns = aiMdAligns(lines[i + 1]);
      i += 2;
      const rows = [];
      while (i < lines.length && lines[i].indexOf('|') !== -1 && lines[i].trim() !== '') { rows.push(aiMdSplitRow(lines[i])); i++; }
      blocks.push({ type: 'table', header, aligns, rows });
      continue;
    }
    // heading
    const h = line.match(/^(#{1,6})\s+(.*)$/);
    if (h) { blocks.push({ type: 'heading', level: h[1].length, text: h[2] }); i++; continue; }
    // hr
    if (/^\s*([-*_])\1\1+\s*$/.test(line)) { blocks.push({ type: 'hr' }); i++; continue; }
    // blockquote
    if (/^\s*>\s?/.test(line)) {
      const buf = [];
      while (i < lines.length && /^\s*>\s?/.test(lines[i])) { buf.push(lines[i].replace(/^\s*>\s?/, '')); i++; }
      blocks.push({ type: 'quote', text: buf.join('\n') });
      continue;
    }
    // unordered list
    if (/^\s*[-*•]\s+/.test(line)) {
      const items = [];
      while (i < lines.length && /^\s*[-*•]\s+/.test(lines[i])) { items.push(lines[i].replace(/^\s*[-*•]\s+/, '')); i++; }
      blocks.push({ type: 'ul', items });
      continue;
    }
    // ordered list
    if (/^\s*\d+[.)]\s+/.test(line)) {
      const items = [];
      while (i < lines.length && /^\s*\d+[.)]\s+/.test(lines[i])) { items.push(lines[i].replace(/^\s*\d+[.)]\s+/, '')); i++; }
      blocks.push({ type: 'ol', items });
      continue;
    }
    // blank
    if (line.trim() === '') { i++; continue; }
    // paragraph
    const buf = [line];
    i++;
    while (i < lines.length && lines[i].trim() !== '' && !aiMdIsSpecial(lines[i], lines[i + 1])) { buf.push(lines[i]); i++; }
    blocks.push({ type: 'p', text: buf.join('\n') });
  }
  return blocks;
}

// ---- Chart spec normalization ----
function aiMdChartPoints(data) {
  if (!Array.isArray(data)) return [];
  return data.map((d) => {
    if (d == null) return { label: '', v1: 0, v2: null };
    const label = d.label != null ? d.label : d.name != null ? d.name : d.x != null ? d.x : d.category != null ? d.category : '';
    let v1 = d.value != null ? d.value : d.v != null ? d.v : d.y != null ? d.y : d.v1 != null ? d.v1 : 0;
    let v2 = d.value2 != null ? d.value2 : d.v2 != null ? d.v2 : null;
    v1 = Number(v1); if (!Number.isFinite(v1)) v1 = 0;
    if (v2 != null) { v2 = Number(v2); if (!Number.isFinite(v2)) v2 = null; }
    return { label: String(label), v1, v2 };
  });
}

function AiMdBarChart({ points, legend }) {
  const W = 480; const H = 210; const padL = 30; const padR = 12; const padT = 16; const padB = 52;
  const plotW = W - padL - padR; const plotH = H - padT - padB;
  const baseY = padT + plotH;
  const n = points.length || 1;
  const hasV2 = points.some((p) => p.v2 != null);
  const vals = [];
  for (let i = 0; i < points.length; i++) { vals.push(points[i].v1); if (points[i].v2 != null) vals.push(points[i].v2); }
  const max = aiMdMax(vals) || 1;
  const groupW = plotW / n;
  const bw = hasV2 ? groupW * 0.32 : groupW * 0.5;
  const rects = [];
  for (let i = 0; i < points.length; i++) {
    const gx = padL + i * groupW + (groupW - (hasV2 ? bw * 2 + 4 : bw)) / 2;
    const h1 = (points[i].v1 / max) * plotH;
    rects.push(React.createElement('rect', { key: 'b1' + i, x: gx, y: baseY - h1, width: bw, height: Math.max(0, h1), rx: 2, fill: AI_MD_PALETTE[0] }));
    rects.push(React.createElement('text', { key: 't1' + i, x: gx + bw / 2, y: baseY - h1 - 3, textAnchor: 'middle' }, aiMdFmtNum(points[i].v1)));
    if (points[i].v2 != null) {
      const h2 = (points[i].v2 / max) * plotH;
      rects.push(React.createElement('rect', { key: 'b2' + i, x: gx + bw + 4, y: baseY - h2, width: bw, height: Math.max(0, h2), rx: 2, fill: AI_MD_PALETTE[1] }));
      rects.push(React.createElement('text', { key: 't2' + i, x: gx + bw + 4 + bw / 2, y: baseY - h2 - 3, textAnchor: 'middle' }, aiMdFmtNum(points[i].v2)));
    }
    rects.push(React.createElement('text', { key: 'lb' + i, x: padL + i * groupW + groupW / 2, y: baseY + 14, textAnchor: 'middle' }, aiMdTrunc(points[i].label, 12)));
  }
  return React.createElement('svg', { viewBox: '0 0 ' + W + ' ' + H, width: '100%', preserveAspectRatio: 'xMidYMid meet', style: { maxWidth: W, height: 'auto', display: 'block' } },
    React.createElement('line', { className: 'axis', x1: padL, y1: baseY, x2: W - padR, y2: baseY }),
    rects,
  );
}

function AiMdLineChart({ points }) {
  const W = 480; const H = 200; const padL = 30; const padR = 12; const padT = 16; const padB = 46;
  const plotW = W - padL - padR; const plotH = H - padT - padB;
  const baseY = padT + plotH;
  const n = points.length;
  const vals = points.map((p) => p.v1);
  const max = aiMdMax(vals) || 1;
  const step = n > 1 ? plotW / (n - 1) : 0;
  const coords = points.map((p, i) => [padL + i * step, baseY - (p.v1 / max) * plotH]);
  let d = '';
  for (let i = 0; i < coords.length; i++) d += (i === 0 ? 'M' : ' L') + coords[i][0].toFixed(1) + ' ' + coords[i][1].toFixed(1);
  const area = d + ' L ' + (padL + (n - 1) * step).toFixed(1) + ' ' + baseY + ' L ' + padL + ' ' + baseY + ' Z';
  const dots = coords.map((c, i) => React.createElement('circle', { key: 'd' + i, cx: c[0], cy: c[1], r: 2.5, fill: AI_MD_PALETTE[0] }));
  const labels = points.map((p, i) => React.createElement('text', { key: 'l' + i, x: coords[i][0], y: baseY + 14, textAnchor: 'middle' }, aiMdTrunc(p.label, 10)));
  const vlabels = points.map((p, i) => React.createElement('text', { key: 'v' + i, x: coords[i][0], y: coords[i][1] - 6, textAnchor: 'middle' }, aiMdFmtNum(p.v1)));
  return React.createElement('svg', { viewBox: '0 0 ' + W + ' ' + H, width: '100%', preserveAspectRatio: 'xMidYMid meet', style: { maxWidth: W, height: 'auto', display: 'block' } },
    React.createElement('line', { className: 'axis', x1: padL, y1: baseY, x2: W - padR, y2: baseY }),
    React.createElement('path', { d: area, fill: AI_MD_PALETTE[0], opacity: 0.12 }),
    React.createElement('path', { d, fill: 'none', stroke: AI_MD_PALETTE[0], strokeWidth: 2 }),
    dots, vlabels, labels,
  );
}

function AiMdPieChart({ points }) {
  const size = 160; const cx = 80; const cy = 80; const r = 70;
  let total = 0;
  for (let i = 0; i < points.length; i++) total += Math.max(0, points[i].v1);
  if (total <= 0) total = 1;
  let a0 = -Math.PI / 2;
  const slices = [];
  for (let i = 0; i < points.length; i++) {
    const frac = Math.max(0, points[i].v1) / total;
    const a1 = a0 + frac * Math.PI * 2;
    const x0 = cx + r * Math.cos(a0); const y0 = cy + r * Math.sin(a0);
    const x1 = cx + r * Math.cos(a1); const y1 = cy + r * Math.sin(a1);
    const laf = frac > 0.5 ? 1 : 0;
    const dPath = points.length === 1
      ? 'M ' + (cx - r) + ' ' + cy + ' A ' + r + ' ' + r + ' 0 1 1 ' + (cx + r) + ' ' + cy + ' A ' + r + ' ' + r + ' 0 1 1 ' + (cx - r) + ' ' + cy + ' Z'
      : 'M ' + cx + ' ' + cy + ' L ' + x0.toFixed(1) + ' ' + y0.toFixed(1) + ' A ' + r + ' ' + r + ' 0 ' + laf + ' 1 ' + x1.toFixed(1) + ' ' + y1.toFixed(1) + ' Z';
    slices.push(React.createElement('path', { key: 's' + i, d: dPath, fill: AI_MD_PALETTE[i % AI_MD_PALETTE.length] }));
    a0 = a1;
  }
  const legend = points.map((p, i) => {
    const pct = Math.round((Math.max(0, p.v1) / total) * 100);
    return React.createElement('span', { key: 'lg' + i },
      React.createElement('i', { style: { background: AI_MD_PALETTE[i % AI_MD_PALETTE.length] } }),
      aiMdTrunc(p.label, 18) + ' · ' + pct + '%');
  });
  return React.createElement('div', { style: { display: 'flex', gap: 14, alignItems: 'center', flexWrap: 'wrap' } },
    React.createElement('svg', { width: size, height: size, viewBox: '0 0 ' + size + ' ' + size, style: { flex: '0 0 auto' } }, slices),
    React.createElement('div', { className: 'legend', style: { flexDirection: 'column', marginTop: 0, gap: 4 } }, legend),
  );
}

function AiMdChart({ raw }) {
  let spec = null;
  try { spec = JSON.parse(raw); } catch (e) { spec = null; }
  if (!spec || typeof spec !== 'object') {
    return React.createElement('pre', { className: 'ai-md-pre' }, React.createElement('code', null, raw));
  }
  const type = String(spec.type || 'bar').toLowerCase();
  const points = aiMdChartPoints(spec.data);
  if (points.length === 0) {
    return React.createElement('pre', { className: 'ai-md-pre' }, React.createElement('code', null, raw));
  }
  const title = spec.title ? React.createElement('div', { className: 'ttl' }, String(spec.title)) : null;
  let body; let legend = null;
  if (type === 'line') {
    body = React.createElement(AiMdLineChart, { points });
  } else if (type === 'pie' || type === 'doughnut') {
    body = React.createElement(AiMdPieChart, { points });
  } else {
    body = React.createElement(AiMdBarChart, { points });
    const hasV2 = points.some((p) => p.v2 != null);
    const names = Array.isArray(spec.legend) ? spec.legend : Array.isArray(spec.series) ? spec.series : ['Serie 1', 'Serie 2'];
    if (hasV2) {
      legend = React.createElement('div', { className: 'legend' },
        React.createElement('span', { key: 'l0' }, React.createElement('i', { style: { background: AI_MD_PALETTE[0] } }), String(names[0] || 'Serie 1')),
        React.createElement('span', { key: 'l1' }, React.createElement('i', { style: { background: AI_MD_PALETTE[1] } }), String(names[1] || 'Serie 2')),
      );
    }
  }
  return React.createElement('div', { className: 'ai-md-chart' }, title, body, legend);
}

// ---- Main renderer ----
function AiMarkdown(props) {
  const text = props && props.text != null ? props.text : '';
  const blocks = aiMdBlocks(text);
  const out = [];
  for (let i = 0; i < blocks.length; i++) {
    const b = blocks[i]; const key = 'blk' + i;
    if (b.type === 'heading') {
      const tag = b.level <= 1 ? 'h4' : b.level === 2 ? 'h5' : 'h6';
      out.push(React.createElement(tag, { key }, aiMdInline(b.text, key + '_')));
    } else if (b.type === 'hr') {
      out.push(React.createElement('hr', { key }));
    } else if (b.type === 'quote') {
      out.push(React.createElement('blockquote', { key }, aiMdMultiline(b.text, key + '_')));
    } else if (b.type === 'ul') {
      out.push(React.createElement('ul', { key }, b.items.map((it, j) => React.createElement('li', { key: j }, aiMdInline(it, key + '_' + j + '_')))));
    } else if (b.type === 'ol') {
      out.push(React.createElement('ol', { key }, b.items.map((it, j) => React.createElement('li', { key: j }, aiMdInline(it, key + '_' + j + '_')))));
    } else if (b.type === 'code') {
      out.push(React.createElement('pre', { key, className: 'ai-md-pre' }, React.createElement('code', null, b.text)));
    } else if (b.type === 'chart') {
      out.push(React.createElement(AiMdChart, { key, raw: b.raw }));
    } else if (b.type === 'table') {
      const cols = b.header.length;
      const thead = React.createElement('thead', { key: 'h' },
        React.createElement('tr', null, b.header.map((c, j) => React.createElement('th', { key: j, style: { textAlign: b.aligns[j] || 'left' } }, aiMdInline(c, key + '_h' + j + '_')))));
      const tbody = React.createElement('tbody', { key: 'b' },
        b.rows.map((row, r) => React.createElement('tr', { key: r },
          (() => { const tds = []; for (let c = 0; c < cols; c++) tds.push(React.createElement('td', { key: c, style: { textAlign: b.aligns[c] || 'left' } }, aiMdInline(row[c] != null ? row[c] : '', key + '_r' + r + 'c' + c + '_'))); return tds; })())));
      out.push(React.createElement('div', { key, className: 'ai-md-tablewrap' }, React.createElement('table', null, thead, tbody)));
    } else {
      out.push(React.createElement('p', { key }, aiMdMultiline(b.text, key + '_')));
    }
  }
  return React.createElement('div', { className: 'ai-md' }, out);
}

Object.assign(window, { AiMarkdown });
