const { useState, useEffect, useRef, useCallback } = React;

const api = {
  get: u => fetch(u).then(r => r.json()),
  post: (u, d) => fetch(u, { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(d) }).then(r => r.json()),
  del: u => fetch(u, { method:'DELETE' }).then(r => r.json()),
  upload: (u, file) => { const fd = new FormData(); fd.append('file', file); return fetch(u, { method:'POST', body:fd }).then(r => r.json()); }
};

// Dark-Theme Plotly-Layout Basis
const DARK_LAYOUT = {
  paper_bgcolor: '#1e293b',
  plot_bgcolor: '#0f172a',
  font: { color: '#e2e8f0', family: 'Arial' },
  xaxis: { gridcolor: '#334155', linecolor: '#475569', tickcolor: '#475569', zeroline: false },
  yaxis: { gridcolor: '#334155', linecolor: '#475569', tickcolor: '#475569', zeroline: false },
  margin: { l: 60, r: 30, t: 60, b: 60 },
  legend: { bgcolor: '#1e293b', bordercolor: '#334155', borderwidth: 1 }
};

const CHART_TYPES = [
  { id:'candlestick', label:'🕯️ Candlestick', desc:'OHLC-Kerzen' },
  { id:'ohlc', label:'📊 OHLC-Balken', desc:'Open-High-Low-Close' },
  { id:'line', label:'📈 Linienchart', desc:'Closing-Prices' },
  { id:'area', label:'🏔️ Area-Chart', desc:'Gefüllte Linie' },
  { id:'volume', label:'📦 Volumen', desc:'Handelsvolumen' },
  { id:'candlestick_volume', label:'🕯️+📦 Candle+Volumen', desc:'Kombiniert' },
  { id:'rsi', label:'⚡ RSI', desc:'Relative Strength Index' },
  { id:'macd', label:'🔀 MACD', desc:'Moving Avg Convergence' },
  { id:'bollinger', label:'🎯 Bollinger Bands', desc:'Volatilitätsbänder' },
  { id:'ichimoku', label:'☁️ Ichimoku', desc:'Ichimoku Cloud' },
  { id:'sma', label:'📉 SMA', desc:'Simple Moving Average' },
  { id:'ema', label:'📉 EMA', desc:'Exponential Moving Avg' },
  { id:'multi', label:'🔧 Multi-Panel', desc:'Candle+RSI+MACD' },
  { id:'heatmap', label:'🌡️ Rendite-Heatmap', desc:'Monatliche Renditen' },
  { id:'scatter', label:'🔵 Scatter', desc:'Korrelation/Vergleich' }
];

// FARBSCHEMAS für Buchsatz
const COLOR_SCHEMES = {
  classic: { up:'#26a69a', down:'#ef5350', line:'#38bdf8', name:'Trading Classic' },
  print_bw: { up:'#333333', down:'#888888', line:'#000000', name:'Druck Graustufen' },
  print_color: { up:'#1a7c4f', down:'#c0392b', line:'#2980b9', name:'Druck Farbe' },
  financial: { up:'#00b894', down:'#d63031', line:'#0984e3', name:'Financial Times' },
  dark_pro: { up:'#00e676', down:'#ff1744', line:'#29b6f6', name:'Dark Pro' }
};

// ======== CHART-RENDERING ========
function renderChart(containerId, chartType, dataset, indData, options = {}) {
  const { ticker, data: rows = [] } = dataset.data || {};
  const scheme = COLOR_SCHEMES[options.colorScheme || 'classic'];
  const dates = rows.map(r => r.date);
  const closes = rows.map(r => r.close);
  const opens = rows.map(r => r.open);
  const highs = rows.map(r => r.high || r.close);
  const lows = rows.map(r => r.low || r.close);
  const vols = rows.map(r => r.volume || 0);

  const layout = {
    ...DARK_LAYOUT,
    title: { text: options.title || ticker || 'Chart', font: { size: 18, color: '#e2e8f0' } },
    height: options.height || 500,
    showlegend: options.showLegend !== false
  };

  let traces = [];

  if (chartType === 'candlestick' || chartType === 'candlestick_volume') {
    traces.push({
      type: 'candlestick', name: ticker || 'Kurs',
      x: dates, open: opens, high: highs, low: lows, close: closes,
      increasing: { line: { color: scheme.up }, fillcolor: scheme.up },
      decreasing: { line: { color: scheme.down }, fillcolor: scheme.down }
    });
    if (chartType === 'candlestick_volume') {
      traces.push({
        type: 'bar', name: 'Volumen', x: dates, y: vols,
        marker: { color: closes.map((c, i) => c >= (opens[i] || c) ? scheme.up + '88' : scheme.down + '88') },
        yaxis: 'y2', showlegend: false
      });
      layout.yaxis2 = { ...DARK_LAYOUT.yaxis, overlaying: 'y', side: 'right', showgrid: false, title: 'Volumen' };
    }
  } else if (chartType === 'ohlc') {
    traces.push({
      type: 'ohlc', name: ticker || 'Kurs',
      x: dates, open: opens, high: highs, low: lows, close: closes,
      increasing: { line: { color: scheme.up } },
      decreasing: { line: { color: scheme.down } }
    });
  } else if (chartType === 'line') {
    traces.push({ type: 'scatter', mode: 'lines', name: ticker || 'Close',
      x: dates, y: closes, line: { color: scheme.line, width: 2 } });
  } else if (chartType === 'area') {
    traces.push({ type: 'scatter', mode: 'lines', name: ticker || 'Close',
      x: dates, y: closes, fill: 'tozeroy',
      line: { color: scheme.line, width: 2 }, fillcolor: scheme.line + '33' });
  } else if (chartType === 'volume') {
    traces.push({
      type: 'bar', name: 'Volumen', x: dates, y: vols,
      marker: { color: closes.map((c, i) => c >= (opens[i] || c) ? scheme.up : scheme.down) }
    });
  } else if (chartType === 'rsi' && indData?.rsi) {
    traces.push({ type: 'scatter', mode: 'lines', name: 'RSI(14)',
      x: dates, y: indData.rsi, line: { color: '#a855f7', width: 2 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Überkauft(70)',
      x: dates, y: Array(dates.length).fill(70), line: { color: '#ef4444', dash: 'dash', width: 1 }, showlegend: false });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Überverkauft(30)',
      x: dates, y: Array(dates.length).fill(30), line: { color: '#22c55e', dash: 'dash', width: 1 }, showlegend: false });
    layout.yaxis = { ...DARK_LAYOUT.yaxis, range: [0, 100], title: 'RSI' };
  } else if (chartType === 'macd' && indData?.macd) {
    const { macdLine, signalLine, histogram } = indData.macd;
    traces.push({ type: 'bar', name: 'Histogramm', x: dates, y: histogram,
      marker: { color: histogram.map(v => v >= 0 ? scheme.up : scheme.down) } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'MACD', x: dates, y: macdLine, line: { color: '#38bdf8', width: 2 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Signal', x: dates, y: signalLine, line: { color: '#f59e0b', width: 2 } });
  } else if (chartType === 'bollinger' && indData?.bollinger) {
    const upper = indData.bollinger.map(b => b.upper);
    const mid   = indData.bollinger.map(b => b.mid);
    const lower = indData.bollinger.map(b => b.lower);
    traces.push({ type: 'scatter', mode: 'lines', name: 'Close', x: dates, y: closes, line: { color: scheme.line, width: 2 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Oberes Band', x: dates, y: upper, line: { color: '#f59e0b', dash: 'dash', width: 1 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Mittleres Band (SMA20)', x: dates, y: mid, line: { color: '#94a3b8', width: 1 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Unteres Band', x: dates, y: lower, fill: 'tonexty', fillcolor: '#f59e0b11', line: { color: '#f59e0b', dash: 'dash', width: 1 } });
  } else if (chartType === 'ichimoku' && indData?.ichimoku) {
    const tenkan  = indData.ichimoku.map(i => i.tenkan);
    const kijun   = indData.ichimoku.map(i => i.kijun);
    const senkouA = indData.ichimoku.map(i => i.senkouA);
    const senkouB = indData.ichimoku.map(i => i.senkouB);
    traces.push({ type: 'candlestick', name: 'Kurs', x: dates, open: opens, high: highs, low: lows, close: closes,
      increasing: { line: { color: scheme.up } }, decreasing: { line: { color: scheme.down } } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Tenkan-sen', x: dates, y: tenkan, line: { color: '#ef4444', width: 1 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Kijun-sen', x: dates, y: kijun, line: { color: '#3b82f6', width: 1 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Senkou A', x: dates, y: senkouA, fill: 'tonexty', fillcolor: '#22c55e22', line: { color: '#22c55e', width: 1 } });
    traces.push({ type: 'scatter', mode: 'lines', name: 'Senkou B', x: dates, y: senkouB, line: { color: '#ef4444', width: 1 } });
  } else if (chartType === 'sma' && indData) {
    traces.push({ type: 'scatter', mode: 'lines', name: 'Close', x: dates, y: closes, line: { color: scheme.line, width: 2 } });
    if (indData.sma20) traces.push({ type: 'scatter', mode: 'lines', name: 'SMA 20', x: dates, y: indData.sma20, line: { color: '#f59e0b', width: 1, dash: 'dot' } });
    if (indData.sma50) traces.push({ type: 'scatter', mode: 'lines', name: 'SMA 50', x: dates, y: indData.sma50, line: { color: '#a855f7', width: 1, dash: 'dot' } });
    if (indData.sma200) traces.push({ type: 'scatter', mode: 'lines', name: 'SMA 200', x: dates, y: indData.sma200, line: { color: '#ef4444', width: 1, dash: 'dot' } });
  } else if (chartType === 'ema' && indData) {
    traces.push({ type: 'scatter', mode: 'lines', name: 'Close', x: dates, y: closes, line: { color: scheme.line, width: 2 } });
    if (indData.ema20) traces.push({ type: 'scatter', mode: 'lines', name: 'EMA 20', x: dates, y: indData.ema20, line: { color: '#f59e0b', width: 1 } });
    if (indData.ema50) traces.push({ type: 'scatter', mode: 'lines', name: 'EMA 50', x: dates, y: indData.ema50, line: { color: '#a855f7', width: 1 } });
  } else if (chartType === 'multi') {
    // Kombinierter Multi-Panel: Candlestick + Volumen + RSI + MACD
    traces = [
      { type:'candlestick', name: ticker||'Kurs', x:dates, open:opens, high:highs, low:lows, close:closes,
        increasing:{line:{color:scheme.up},fillcolor:scheme.up}, decreasing:{line:{color:scheme.down},fillcolor:scheme.down}, xaxis:'x', yaxis:'y' },
      { type:'bar', name:'Volumen', x:dates, y:vols, marker:{color:closes.map((c,i)=>c>=(opens[i]||c)?scheme.up+'88':scheme.down+'88')}, xaxis:'x', yaxis:'y2' }
    ];
    if (indData?.rsi) traces.push({ type:'scatter', mode:'lines', name:'RSI', x:dates, y:indData.rsi, line:{color:'#a855f7',width:2}, xaxis:'x', yaxis:'y3' });
    if (indData?.macd) {
      traces.push({ type:'bar', name:'MACD Hist', x:dates, y:indData.macd.histogram, marker:{color:indData.macd.histogram.map(v=>v>=0?scheme.up:scheme.down)}, xaxis:'x', yaxis:'y4' });
      traces.push({ type:'scatter', mode:'lines', name:'MACD', x:dates, y:indData.macd.macdLine, line:{color:'#38bdf8',width:1}, xaxis:'x', yaxis:'y4' });
    }
    layout.grid = { rows: 4, columns: 1, pattern: 'independent', roworder: 'top to bottom' };
    layout.height = options.height || 900;
    layout.yaxis  = { ...DARK_LAYOUT.yaxis, domain:[0.55,1],   title:'Kurs' };
    layout.yaxis2 = { ...DARK_LAYOUT.yaxis, domain:[0.38,0.53], title:'Vol', showgrid:false };
    layout.yaxis3 = { ...DARK_LAYOUT.yaxis, domain:[0.20,0.36], title:'RSI', range:[0,100] };
    layout.yaxis4 = { ...DARK_LAYOUT.yaxis, domain:[0.0,0.18],  title:'MACD' };
    layout.xaxis2 = { ...DARK_LAYOUT.xaxis, anchor:'y2' };
    layout.xaxis3 = { ...DARK_LAYOUT.xaxis, anchor:'y3' };
    layout.xaxis4 = { ...DARK_LAYOUT.xaxis, anchor:'y4' };
  } else if (chartType === 'heatmap') {
    // Monatliche Renditen-Heatmap
    const monthlyMap = {};
    rows.forEach((r, i) => {
      if (i === 0) return;
      const d = new Date(r.date);
      const yr = d.getFullYear();
      const mo = d.getMonth();
      if (!monthlyMap[yr]) monthlyMap[yr] = new Array(12).fill(null);
      const prev = rows[i-1].close;
      if (prev) monthlyMap[yr][mo] = ((r.close - prev) / prev) * 100;
    });
    const years = Object.keys(monthlyMap).sort();
    const months = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'];
    traces = [{
      type: 'heatmap',
      x: months, y: years,
      z: years.map(y => monthlyMap[y]),
      colorscale: [[0,'#c0392b'],[0.5,'#1e293b'],[1,'#27ae60']],
      text: years.map(y => monthlyMap[y].map(v => v !== null ? v.toFixed(1)+'%' : '')),
      texttemplate: '%{text}',
      showscale: true
    }];
    layout.yaxis = { ...DARK_LAYOUT.yaxis, type: 'category' };
  } else if (chartType === 'scatter') {
    traces.push({ type:'scatter', mode:'markers', name: ticker||'Kurs',
      x: dates, y: closes,
      marker: { color: closes, colorscale:'RdYlGn', size:6, showscale:true } });
  } else {
    // Fallback: Linie
    traces.push({ type:'scatter', mode:'lines', name: ticker||'Close', x:dates, y:closes, line:{color:scheme.line,width:2} });
  }

  Plotly.newPlot(containerId, traces, layout, {
    responsive: true,
    displayModeBar: true,
    modeBarButtonsToAdd: ['drawline','drawopenpath','eraseshape'],
    toImageButtonOptions: { format:'png', width:1920, height:1080, scale:2 }
  });
}

// ======== MANUELLE DATENEINGABE ========
function ManualInput({ onSave }) {
  const [ticker, setTicker] = useState('');
  const [rows, setRows] = useState([
    { date:'2024-01-02', open:100, high:105, low:98, close:103, volume:1000000 },
    { date:'2024-01-03', open:103, high:108, low:101, close:106, volume:1200000 },
    { date:'2024-01-04', open:106, high:107, low:100, close:102, volume:900000 },
    { date:'2024-01-05', open:102, high:110, low:101, close:109, volume:1500000 },
    { date:'2024-01-08', open:109, high:112, low:107, close:111, volume:1100000 }
  ]);
  const [newRow, setNewRow] = useState({ date:'', open:'', high:'', low:'', close:'', volume:'' });

  function addRow() {
    if (!newRow.date || !newRow.close) return;
    setRows([...rows, {
      date: newRow.date,
      open: parseFloat(newRow.open) || parseFloat(newRow.close),
      high: parseFloat(newRow.high) || parseFloat(newRow.close),
      low: parseFloat(newRow.low) || parseFloat(newRow.close),
      close: parseFloat(newRow.close),
      volume: parseFloat(newRow.volume) || 0
    }]);
    setNewRow({ date:'', open:'', high:'', low:'', close:'', volume:'' });
  }
  function delRow(i) { setRows(rows.filter((_, j) => j !== i)); }
  function updateRow(i, field, val) {
    const nr = [...rows]; nr[i] = { ...nr[i], [field]: isNaN(val) ? val : parseFloat(val) || val };
    setRows(nr);
  }

  return (
    <div className="space-y-4">
      <input type="text" value={ticker} onChange={e => setTicker(e.target.value)}
        placeholder="Ticker/Firmenname (z.B. AAPL, Siemens AG)" className="w-full" />

      <div className="overflow-x-auto">
        <table className="w-full text-sm">
          <thead>
            <tr className="text-gray-400 border-b border-slate-700">
              {['Datum','Open','High','Low','Close','Volume',''].map(h => <th key={h} className="text-left px-2 py-1">{h}</th>)}
            </tr>
          </thead>
          <tbody>
            {rows.map((r, i) => (
              <tr key={i} className="border-b border-slate-800">
                {['date','open','high','low','close','volume'].map(f => (
                  <td key={f} className="px-1 py-1">
                    <input type={f==='date'?'date':'number'} value={r[f]}
                      onChange={e => updateRow(i, f, e.target.value)}
                      className="w-full text-xs py-1" style={{minWidth: f==='date'?'120px':'70px'}} />
                  </td>
                ))}
                <td className="px-1"><button onClick={() => delRow(i)} className="text-red-400 hover:text-red-300 text-xs">✕</button></td>
              </tr>
            ))}
            <tr className="border-b border-slate-700 bg-slate-900">
              {['date','open','high','low','close','volume'].map(f => (
                <td key={f} className="px-1 py-1">
                  <input type={f==='date'?'date':'number'} value={newRow[f]}
                    onChange={e => setNewRow({...newRow, [f]: e.target.value})}
                    placeholder={f} className="w-full text-xs py-1" style={{minWidth: f==='date'?'120px':'70px'}} />
                </td>
              ))}
              <td className="px-1"><button onClick={addRow} className="text-green-400 hover:text-green-300 text-xs">+</button></td>
            </tr>
          </tbody>
        </table>
      </div>

      <button onClick={() => onSave({ ticker, data: rows })}
        className="btn-primary px-4 py-2 rounded text-sm">
        Dataset speichern ({rows.length} Einträge)
      </button>
    </div>
  );
}

// ======== CHART-BUILDER ========
function ChartBuilder({ dataset, onExport }) {
  const chartRef = useRef(null);
  const [chartType, setChartType] = useState('candlestick');
  const [colorScheme, setColorScheme] = useState('classic');
  const [title, setTitle] = useState('');
  const [height, setHeight] = useState(500);
  const [indData, setIndData] = useState(null);
  const [loading, setLoading] = useState(false);

  const NEEDS_IND = ['rsi','macd','bollinger','ichimoku','sma','ema','multi'];

  async function loadIndicators() {
    if (!NEEDS_IND.includes(chartType)) return null;
    const types = {
      rsi: ['rsi'], macd: ['macd'], bollinger: ['bollinger'],
      ichimoku: ['ichimoku'], sma: ['sma20','sma50','sma200'],
      ema: ['ema20','ema50'], multi: ['rsi','macd']
    }[chartType] || [];
    const r = await api.post(`/api/datasets/${dataset.id}/indicators`, { types });
    return r.indicators;
  }

  async function draw() {
    setLoading(true);
    const ind = await loadIndicators();
    setIndData(ind);
    const ds = { ...dataset, data: typeof dataset.data === 'string' ? JSON.parse(dataset.data) : dataset.data };
    renderChart('chartContainer', chartType, ds, ind, {
      colorScheme, title: title || ds.data?.ticker || 'Chart', height
    });
    setLoading(false);
  }

  useEffect(() => { draw(); }, [chartType, colorScheme, height, dataset]);

  function exportPNG() {
    Plotly.downloadImage('chartContainer', {
      format: 'png', width: 1920, height: height * 2, scale: 2,
      filename: `chart_${chartType}_${Date.now()}`
    });
  }
  function exportSVG() {
    Plotly.downloadImage('chartContainer', {
      format: 'svg', width: 1920, height: height * 2,
      filename: `chart_${chartType}_${Date.now()}`
    });
  }

  return (
    <div className="space-y-4">
      <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
        <div>
          <label className="block text-xs text-gray-400 mb-1">Chart-Typ</label>
          <select value={chartType} onChange={e => setChartType(e.target.value)} className="w-full text-sm">
            {CHART_TYPES.map(t => <option key={t.id} value={t.id}>{t.label}</option>)}
          </select>
        </div>
        <div>
          <label className="block text-xs text-gray-400 mb-1">Farbschema</label>
          <select value={colorScheme} onChange={e => setColorScheme(e.target.value)} className="w-full text-sm">
            {Object.entries(COLOR_SCHEMES).map(([k,v]) => <option key={k} value={k}>{v.name}</option>)}
          </select>
        </div>
        <div>
          <label className="block text-xs text-gray-400 mb-1">Titel</label>
          <input type="text" value={title} onChange={e => setTitle(e.target.value)}
            placeholder="Chart-Titel" className="w-full text-sm" />
        </div>
        <div>
          <label className="block text-xs text-gray-400 mb-1">Höhe (px)</label>
          <select value={height} onChange={e => setHeight(parseInt(e.target.value))} className="w-full text-sm">
            {[400,500,600,700,800,900].map(h => <option key={h} value={h}>{h}px</option>)}
          </select>
        </div>
      </div>

      <div className="flex gap-2">
        <button onClick={draw} className="btn-primary px-4 py-2 rounded text-sm" disabled={loading}>
          {loading ? '⏳ Lade...' : '🔄 Aktualisieren'}
        </button>
        <button onClick={exportPNG} className="btn-ghost px-4 py-2 rounded text-sm">📸 PNG (300dpi)</button>
        <button onClick={exportSVG} className="btn-ghost px-4 py-2 rounded text-sm">📐 SVG (Vektor)</button>
      </div>

      <div id="chartContainer" className="dark-card rounded-lg" style={{minHeight:'400px'}}></div>

      <div className="text-xs text-gray-500 p-3 dark-card rounded">
        💡 <strong>Für Buchsatz:</strong> PNG 2× Skalierung → 300 DPI bei 96dpi-Bildschirm. SVG = verlustfrei skalierbar.
        Farbschema <em>Druck Graustufen</em> für S/W-Druck wählen.
      </div>
    </div>
  );
}

// ======== HAUPT-APP ========
function App() {
  const [projects, setProjects] = useState([]);
  const [pid, setPid] = useState(null);
  const [tab, setTab] = useState('data'); // data | chart
  const [datasets, setDatasets] = useState([]);
  const [selDs, setSelDs] = useState(null);
  const [inputMode, setInputMode] = useState('manual'); // manual | upload
  const [health, setHealth] = useState({ ollama: false });
  const [uploading, setUploading] = useState(false);
  const [uploadResult, setUploadResult] = useState(null);

  useEffect(() => {
    api.get('/api/health').then(setHealth);
    api.get('/api/projects').then(setProjects);
  }, []);

  useEffect(() => {
    if (pid) api.get(`/api/projects/${pid}/datasets`).then(d => { setDatasets(d); if (d.length) setSelDs(d[0]); });
  }, [pid]);

  async function createProject(title) {
    const p = await api.post('/api/projects', { title });
    const updated = await api.get('/api/projects');
    setProjects(updated);
    setPid(p.id);
    setTab('data');
  }

  async function saveManual(data) {
    const name = data.ticker || 'Datensatz';
    await api.post(`/api/projects/${pid}/datasets`, { name, data });
    const updated = await api.get(`/api/projects/${pid}/datasets`);
    setDatasets(updated);
    setSelDs(updated[0]);
    setTab('chart');
  }

  async function handleUpload(e) {
    const file = e.target.files[0]; if (!file) return;
    setUploading(true); setUploadResult(null);
    const r = await api.upload(`/api/projects/${pid}/upload`, file);
    setUploadResult(r);
    const updated = await api.get(`/api/projects/${pid}/datasets`);
    setDatasets(updated);
    if (updated.length) setSelDs(updated[0]);
    setUploading(false);
  }

  async function delDs(id) {
    await api.del('/api/datasets/' + id);
    const updated = await api.get(`/api/projects/${pid}/datasets`);
    setDatasets(updated);
    setSelDs(updated[0] || null);
  }

  if (!pid) return (
    <div className="min-h-screen p-6">
      <div className="max-w-4xl mx-auto">
        <div className="flex items-center justify-between mb-8">
          <div>
            <h1 className="text-3xl font-bold accent">📈 Trading Charts</h1>
            <p className="text-gray-400 mt-1">Professionelle Grafiken für dein Tradingbuch</p>
          </div>
          <div className={`px-3 py-1 rounded text-sm ${health.ollama ? 'bg-green-900 text-green-300' : 'bg-red-900 text-red-300'}`}>
            KI: {health.ollama ? '✓ Online' : '✗ Offline'}
          </div>
        </div>

        <div className="dark-card rounded-lg p-6 mb-6">
          <h3 className="font-bold mb-3">Neues Projekt</h3>
          <div className="flex gap-3">
            <input type="text" id="ptitle" placeholder="z.B. Kapitel 3 – Trendanalyse" className="flex-1" />
            <button onClick={() => {
              const t = document.getElementById('ptitle').value.trim();
              if (t) createProject(t);
            }} className="btn-primary px-4 py-2 rounded">Erstellen</button>
          </div>
        </div>

        <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
          {projects.map(p => (
            <div key={p.id} className="dark-card rounded-lg p-4 cursor-pointer hover:border-sky-500 transition"
              onClick={() => { setPid(p.id); setTab('data'); }}>
              <h3 className="font-bold">{p.title}</h3>
              <p className="text-xs text-gray-500 mt-1">{p.updated_at?.substring(0,10)}</p>
            </div>
          ))}
        </div>
      </div>
    </div>
  );

  return (
    <div className="min-h-screen">
      <header className="bg-slate-800 border-b border-slate-700 p-4 flex items-center justify-between">
        <div className="flex items-center gap-4">
          <button onClick={() => { setPid(null); setDatasets([]); setSelDs(null); }}
            className="text-gray-400 hover:text-white">← Projekte</button>
          <h1 className="font-bold accent">📈 Trading Charts</h1>
        </div>
        <div className={`px-2 py-1 rounded text-xs ${health.ollama ? 'bg-green-900 text-green-300' : 'bg-red-900 text-red-300'}`}>
          KI: {health.ollama ? '✓' : '✗'}
        </div>
      </header>

      <div className="flex border-b border-slate-700">
        {[['data','📊 Daten'],['chart','📈 Charts']].map(([k,l]) => (
          <button key={k} onClick={() => setTab(k)}
            className={`px-6 py-3 text-sm ${tab===k ? 'border-b-2 border-sky-400 text-sky-400' : 'text-gray-400 hover:text-white'}`}>
            {l}
          </button>
        ))}
      </div>

      <div className="p-6 max-w-7xl mx-auto">
        {tab === 'data' && (
          <div className="grid md:grid-cols-3 gap-6">
            <div className="md:col-span-2 space-y-4">
              <div className="dark-card rounded-lg p-4">
                <div className="flex gap-2 mb-4">
                  <button onClick={() => setInputMode('manual')}
                    className={`px-4 py-2 rounded text-sm ${inputMode==='manual' ? 'btn-primary' : 'btn-ghost'}`}>
                    ✏️ Manuell eingeben
                  </button>
                  <button onClick={() => setInputMode('upload')}
                    className={`px-4 py-2 rounded text-sm ${inputMode==='upload' ? 'btn-primary' : 'btn-ghost'}`}>
                    📄 Buchseite / CSV hochladen
                  </button>
                </div>

                {inputMode === 'manual' && <ManualInput onSave={saveManual} />}

                {inputMode === 'upload' && (
                  <div className="space-y-4">
                    <p className="text-sm text-gray-400">
                      Unterstützte Formate: <strong>CSV</strong> (date,open,high,low,close,volume),
                      <strong> TXT</strong> (Buchseite mit Kursdaten → KI extrahiert automatisch)
                    </p>
                    <input type="file" accept=".csv,.txt" onChange={handleUpload} className="w-full" />
                    {uploading && <p className="text-sky-400 text-sm">⏳ KI extrahiert Daten...</p>}
                    {uploadResult && (
                      <div className="bg-green-900 bg-opacity-30 border border-green-700 rounded p-3 text-sm">
                        <p className="font-bold text-green-400">✓ Extrahiert</p>
                        <p>Ticker: {uploadResult.extracted?.ticker || '?'}</p>
                        <p>Datenpunkte: {uploadResult.extracted?.data?.length || 0}</p>
                        {uploadResult.extracted?.notes && <p className="text-gray-400 text-xs mt-1">{uploadResult.extracted.notes}</p>}
                        <button onClick={() => setTab('chart')} className="btn-primary px-3 py-1 rounded text-xs mt-2">
                          → Chart erstellen
                        </button>
                      </div>
                    )}
                  </div>
                )}
              </div>
            </div>

            <div>
              <h3 className="font-bold mb-3 text-sm text-gray-400">Gespeicherte Datasets</h3>
              <div className="space-y-2">
                {datasets.map(ds => (
                  <div key={ds.id} onClick={() => setSelDs(ds)}
                    className={`dark-card rounded p-3 cursor-pointer transition ${selDs?.id === ds.id ? 'border-sky-500' : 'hover:border-slate-500'}`}>
                    <div className="flex justify-between items-start">
                      <div>
                        <p className="font-semibold text-sm">{ds.name}</p>
                        <p className="text-xs text-gray-500">{ds.data?.data?.length || 0} Datenpunkte</p>
                        <p className="text-xs text-gray-600">{ds.source}</p>
                      </div>
                      <button onClick={e => { e.stopPropagation(); delDs(ds.id); }}
                        className="text-red-500 text-xs hover:text-red-400">✕</button>
                    </div>
                  </div>
                ))}
                {datasets.length === 0 && (
                  <p className="text-gray-600 text-sm">Noch keine Datasets</p>
                )}
              </div>
              {selDs && (
                <button onClick={() => setTab('chart')} className="btn-primary w-full py-2 rounded mt-4 text-sm">
                  → Chart erstellen
                </button>
              )}
            </div>
          </div>
        )}

        {tab === 'chart' && (
          selDs ? (
            <div>
              <div className="flex items-center gap-4 mb-4">
                <span className="text-sm text-gray-400">Dataset:</span>
                <select value={selDs.id}
                  onChange={e => setSelDs(datasets.find(d => d.id === e.target.value))}
                  className="text-sm">
                  {datasets.map(d => <option key={d.id} value={d.id}>{d.name}</option>)}
                </select>
              </div>
              <ChartBuilder dataset={selDs} />
            </div>
          ) : (
            <div className="text-center py-20">
              <p className="text-gray-400 mb-4">Zuerst ein Dataset anlegen</p>
              <button onClick={() => setTab('data')} className="btn-primary px-6 py-2 rounded">
                → Daten eingeben
              </button>
            </div>
          )
        )}
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

// ======== WORD-EXPORT TAB ========
function WordExportTab({ pid }) {
  const [step, setStep] = useState(1);
  const [docxInfo, setDocxInfo] = useState(null);
  const [docxId, setDocxId] = useState(null);
  const [imagePath, setImagePath] = useState('');
  const [imageFilename, setImageFilename] = useState('');
  const [insertMode, setInsertMode] = useState('heading');
  const [insertAfter, setInsertAfter] = useState('');
  const [caption, setCaption] = useState('');
  const [figureNumber, setFigureNumber] = useState(1);
  const [widthCm, setWidthCm] = useState(14);
  const [heightCm, setHeightCm] = useState(9);
  const [alignment, setAlignment] = useState('center');
  const [loading, setLoading] = useState(false);
  const [previewPara, setPreviewPara] = useState(null);

  async function uploadDocx(e) {
    const file = e.target.files[0]; if (!file) return;
    setLoading(true);
    const fd = new FormData(); fd.append('docx', file);
    const r = await fetch('/api/word/parse', { method: 'POST', body: fd }).then(x => x.json());
    setDocxInfo(r);
    setDocxId(r.id);
    setLoading(false);
    setStep(2);
  }

  async function uploadImage(e) {
    const file = e.target.files[0]; if (!file) return;
    setLoading(true);
    const fd = new FormData(); fd.append('image', file);
    const r = await fetch('/api/word/upload-image', { method: 'POST', body: fd }).then(x => x.json());
    setImagePath(r.path);
    setImageFilename(r.filename);
    setLoading(false);
  }

  function findPreview() {
    if (!docxInfo) return;
    const paras = docxInfo.paragraphs || [];
    if (insertMode === 'paragraph') {
      const idx = parseInt(insertAfter) - 1;
      setPreviewPara(paras[idx] || null);
    } else {
      const term = insertAfter.toLowerCase();
      const found = paras.find(p => p.toLowerCase().includes(term));
      setPreviewPara(found || null);
    }
  }

  async function doExport() {
    if (!docxId || !imagePath) { alert('DOCX und Grafik müssen hochgeladen sein'); return; }
    setLoading(true);
    const r = await fetch('/api/word/insert', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        docxId, imagePath, insertMode, insertAfter,
        caption, figureNumber, imageWidthCm: widthCm,
        imageHeightCm: heightCm, alignment
      })
    });
    if (!r.ok) {
      const err = await r.json();
      alert('Fehler: ' + err.error);
      setLoading(false);
      return;
    }
    const blob = await r.blob();
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = `kapitel_mit_grafik.docx`; a.click();
    URL.revokeObjectURL(url);
    setLoading(false);
  }

  return (
    <div className="max-w-4xl space-y-6">
      <h2 className="text-xl font-bold accent">📄 Grafik in Word einfügen</h2>

      {/* SCHRITT 1: DOCX hochladen */}
      <div className={`dark-card rounded-lg p-5 ${step >= 1 ? '' : 'opacity-50'}`}>
        <h3 className="font-bold mb-3 flex items-center gap-2">
          <span className={`w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${step >= 1 ? 'bg-sky-500' : 'bg-slate-600'}`}>1</span>
          Buchkapitel hochladen (DOCX)
        </h3>
        <input type="file" accept=".docx" onChange={uploadDocx} className="w-full" />
        {loading && step === 1 && <p className="text-sky-400 text-sm mt-2">⏳ Analysiere DOCX...</p>}
        {docxInfo && (
          <div className="mt-3 p-3 bg-green-900 bg-opacity-30 border border-green-700 rounded text-sm">
            <p className="text-green-400 font-bold">✓ {docxInfo.paragraphCount} Absätze erkannt</p>
            <p className="text-gray-400 mt-1">Überschriften: {(docxInfo.headings || []).map(h => h.text).join(', ') || 'keine'}</p>
          </div>
        )}
      </div>

      {/* SCHRITT 2: Grafik wählen */}
      <div className={`dark-card rounded-lg p-5 ${step >= 2 ? '' : 'opacity-40 pointer-events-none'}`}>
        <h3 className="font-bold mb-3 flex items-center gap-2">
          <span className={`w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${step >= 2 ? 'bg-sky-500' : 'bg-slate-600'}`}>2</span>
          Grafik auswählen (PNG/JPG)
        </h3>
        <p className="text-xs text-gray-400 mb-2">
          💡 In der Charts-Ansicht erst PNG exportieren, dann hier hochladen.
        </p>
        <input type="file" accept=".png,.jpg,.jpeg" onChange={uploadImage} className="w-full" />
        {imageFilename && (
          <p className="text-green-400 text-sm mt-2">✓ {imageFilename}</p>
        )}
        {imageFilename && (
          <button onClick={() => setStep(3)} className="btn-primary px-4 py-2 rounded text-sm mt-3">
            Weiter →
          </button>
        )}
      </div>

      {/* SCHRITT 3: Einfügeposition */}
      <div className={`dark-card rounded-lg p-5 ${step >= 3 ? '' : 'opacity-40 pointer-events-none'}`}>
        <h3 className="font-bold mb-4 flex items-center gap-2">
          <span className={`w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${step >= 3 ? 'bg-sky-500' : 'bg-slate-600'}`}>3</span>
          Einfügeposition bestimmen
        </h3>

        <div className="grid md:grid-cols-2 gap-4 mb-4">
          <div>
            <label className="block text-xs text-gray-400 mb-1">Methode</label>
            <select value={insertMode} onChange={e => { setInsertMode(e.target.value); setInsertAfter(''); setPreviewPara(null); }} className="w-full">
              <option value="heading">Nach Überschrift</option>
              <option value="search">Nach Suchbegriff/Wort</option>
              <option value="paragraph">Nach Absatz-Nummer</option>
            </select>
          </div>
          <div>
            <label className="block text-xs text-gray-400 mb-1">
              {insertMode === 'heading' ? 'Überschrift (ganz oder teilweise)' :
               insertMode === 'search' ? 'Suchbegriff im Text' :
               'Absatz-Nummer (1 = nach erstem Absatz)'}
            </label>
            {insertMode === 'paragraph' ? (
              <input type="number" min="1" max={docxInfo?.paragraphCount || 999}
                value={insertAfter} onChange={e => { setInsertAfter(e.target.value); setPreviewPara(null); }}
                placeholder={`1 - ${docxInfo?.paragraphCount || '?'}`} className="w-full" />
            ) : insertMode === 'heading' ? (
              <select value={insertAfter} onChange={e => { setInsertAfter(e.target.value); setPreviewPara(null); }} className="w-full">
                <option value="">-- Überschrift wählen --</option>
                {(docxInfo?.headings || []).map((h, i) => (
                  <option key={i} value={h.text}>{'  '.repeat(h.level - 1)}{h.text}</option>
                ))}
              </select>
            ) : (
              <input type="text" value={insertAfter}
                onChange={e => { setInsertAfter(e.target.value); setPreviewPara(null); }}
                placeholder="z.B. Aufwärtstrend" className="w-full" />
            )}
          </div>
        </div>

        {insertAfter && (
          <button onClick={findPreview} className="btn-ghost px-3 py-1 rounded text-sm mb-3">
            🔍 Position vorschauen
          </button>
        )}
        {previewPara !== null && (
          <div className="p-3 bg-yellow-900 bg-opacity-30 border border-yellow-700 rounded text-sm mb-4">
            <p className="text-yellow-400 font-bold text-xs mb-1">Grafik wird eingefügt nach:</p>
            <p className="text-gray-300 italic">„{previewPara ? previewPara.substring(0, 120) + '...' : '(Ende des Dokuments)'}"</p>
          </div>
        )}

        {insertAfter && (
          <button onClick={() => setStep(4)} className="btn-primary px-4 py-2 rounded text-sm">
            Weiter →
          </button>
        )}
      </div>

      {/* SCHRITT 4: Bildoptionen */}
      <div className={`dark-card rounded-lg p-5 ${step >= 4 ? '' : 'opacity-40 pointer-events-none'}`}>
        <h3 className="font-bold mb-4 flex items-center gap-2">
          <span className={`w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${step >= 4 ? 'bg-sky-500' : 'bg-slate-600'}`}>4</span>
          Bildoptionen & Bildunterschrift
        </h3>

        <div className="grid md:grid-cols-2 gap-4 mb-4">
          <div>
            <label className="block text-xs text-gray-400 mb-1">Bildunterschrift</label>
            <input type="text" value={caption} onChange={e => setCaption(e.target.value)}
              placeholder="z.B. DAX Wochenchart mit Bollinger Bändern" className="w-full" />
            <p className="text-xs text-gray-500 mt-1">Wird als „Abb. {figureNumber}: {caption || '...'}" eingefügt</p>
          </div>
          <div>
            <label className="block text-xs text-gray-400 mb-1">Abbildungsnummer</label>
            <input type="number" min="1" value={figureNumber} onChange={e => setFigureNumber(parseInt(e.target.value))}
              className="w-full" />
          </div>
          <div>
            <label className="block text-xs text-gray-400 mb-1">Breite (cm)</label>
            <input type="number" min="4" max="20" step="0.5" value={widthCm}
              onChange={e => setWidthCm(parseFloat(e.target.value))} className="w-full" />
          </div>
          <div>
            <label className="block text-xs text-gray-400 mb-1">Höhe (cm)</label>
            <input type="number" min="3" max="20" step="0.5" value={heightCm}
              onChange={e => setHeightCm(parseFloat(e.target.value))} className="w-full" />
          </div>
          <div>
            <label className="block text-xs text-gray-400 mb-1">Ausrichtung</label>
            <select value={alignment} onChange={e => setAlignment(e.target.value)} className="w-full">
              <option value="center">Zentriert</option>
              <option value="left">Links</option>
              <option value="right">Rechts</option>
            </select>
          </div>
          <div className="flex items-end">
            <div className="text-xs text-gray-500 p-3 bg-slate-900 rounded w-full">
              <p>📐 {widthCm} × {heightCm} cm</p>
              <p>Abb. {figureNumber}: {caption || '(Bildunterschrift)'}</p>
              <p>Ausrichtung: {alignment}</p>
            </div>
          </div>
        </div>

        <button onClick={doExport} disabled={loading}
          className="btn-primary px-6 py-3 rounded font-bold disabled:opacity-50">
          {loading ? '⏳ Erstelle DOCX...' : '📥 DOCX mit Grafik herunterladen'}
        </button>
      </div>
    </div>
  );
}

// ======== APP MIT WORD-TAB ========
function AppWithWord() {
  const [projects, setProjects] = useState([]);
  const [pid, setPid] = useState(null);
  const [tab, setTab] = useState('data');
  const [datasets, setDatasets] = useState([]);
  const [selDs, setSelDs] = useState(null);
  const [inputMode, setInputMode] = useState('manual');
  const [health, setHealth] = useState({ ollama: false });
  const [uploading, setUploading] = useState(false);
  const [uploadResult, setUploadResult] = useState(null);

  useEffect(() => {
    api.get('/api/health').then(setHealth);
    api.get('/api/projects').then(setProjects);
  }, []);

  useEffect(() => {
    if (pid) api.get(`/api/projects/${pid}/datasets`).then(d => { setDatasets(d); if (d.length) setSelDs(d[0]); });
  }, [pid]);

  async function createProject(title) {
    const p = await api.post('/api/projects', { title });
    const updated = await api.get('/api/projects');
    setProjects(updated);
    setPid(p.id);
    setTab('data');
  }
  async function saveManual(data) {
    const name = data.ticker || 'Datensatz';
    await api.post(`/api/projects/${pid}/datasets`, { name, data });
    const updated = await api.get(`/api/projects/${pid}/datasets`);
    setDatasets(updated);
    setSelDs(updated[0]);
    setTab('chart');
  }
  async function handleUpload(e) {
    const file = e.target.files[0]; if (!file) return;
    setUploading(true); setUploadResult(null);
    const r = await api.upload(`/api/projects/${pid}/upload`, file);
    setUploadResult(r);
    const updated = await api.get(`/api/projects/${pid}/datasets`);
    setDatasets(updated);
    if (updated.length) setSelDs(updated[0]);
    setUploading(false);
  }
  async function delDs(id) {
    await api.del('/api/datasets/' + id);
    const updated = await api.get(`/api/projects/${pid}/datasets`);
    setDatasets(updated);
    setSelDs(updated[0] || null);
  }

  if (!pid) return (
    <div className="min-h-screen p-6">
      <div className="max-w-4xl mx-auto">
        <div className="flex items-center justify-between mb-8">
          <div>
            <h1 className="text-3xl font-bold accent">📈 Trading Charts</h1>
            <p className="text-gray-400 mt-1">Professionelle Buchgrafiken + Word-Export</p>
          </div>
          <div className={`px-3 py-1 rounded text-sm ${health.ollama ? 'bg-green-900 text-green-300' : 'bg-red-900 text-red-300'}`}>
            KI: {health.ollama ? '✓ Online' : '✗ Offline'}
          </div>
        </div>
        <div className="dark-card rounded-lg p-6 mb-6">
          <h3 className="font-bold mb-3">Neues Projekt</h3>
          <div className="flex gap-3">
            <input type="text" id="ptitle2" placeholder="z.B. Kapitel 3 – Trendanalyse" className="flex-1" />
            <button onClick={() => { const t = document.getElementById('ptitle2').value.trim(); if (t) createProject(t); }}
              className="btn-primary px-4 py-2 rounded">Erstellen</button>
          </div>
        </div>

        {/* Word-Export auch ohne Projekt direkt nutzbar */}
        <div className="dark-card rounded-lg p-6 mb-6 border border-sky-800">
          <h3 className="font-bold mb-2">📄 Direkt: Grafik in Word einfügen</h3>
          <p className="text-sm text-gray-400 mb-3">Kein Projekt nötig – einfach DOCX und PNG hochladen.</p>
          <button onClick={() => { setPid('__direct__'); setTab('word'); }} className="btn-primary px-4 py-2 rounded text-sm">
            Word-Export öffnen →
          </button>
        </div>

        <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
          {projects.map(p => (
            <div key={p.id} className="dark-card rounded-lg p-4 cursor-pointer hover:border-sky-500 transition"
              onClick={() => { setPid(p.id); setTab('data'); }}>
              <h3 className="font-bold">{p.title}</h3>
              <p className="text-xs text-gray-500 mt-1">{p.updated_at?.substring(0,10)}</p>
            </div>
          ))}
        </div>
      </div>
    </div>
  );

  return (
    <div className="min-h-screen">
      <header className="bg-slate-800 border-b border-slate-700 p-4 flex items-center justify-between">
        <div className="flex items-center gap-4">
          <button onClick={() => { setPid(null); setDatasets([]); setSelDs(null); }} className="text-gray-400 hover:text-white">← Projekte</button>
          <h1 className="font-bold accent">📈 Trading Charts</h1>
        </div>
        <div className={`px-2 py-1 rounded text-xs ${health.ollama ? 'bg-green-900 text-green-300' : 'bg-red-900 text-red-300'}`}>
          KI: {health.ollama ? '✓' : '✗'}
        </div>
      </header>

      <div className="flex border-b border-slate-700 overflow-x-auto">
        {[['data','📊 Daten'],['chart','📈 Charts'],['word','📄 Word-Export'],['pipeline','🤖 KI-Pipeline']].map(([k,l]) => (
          <button key={k} onClick={() => setTab(k)}
            className={`px-6 py-3 text-sm whitespace-nowrap ${tab===k ? 'border-b-2 border-sky-400 text-sky-400' : 'text-gray-400 hover:text-white'}`}>
            {l}
          </button>
        ))}
      </div>

      <div className="p-6 max-w-7xl mx-auto">
        {tab === 'data' && (
          <div className="grid md:grid-cols-3 gap-6">
            <div className="md:col-span-2 space-y-4">
              <div className="dark-card rounded-lg p-4">
                <div className="flex gap-2 mb-4">
                  <button onClick={() => setInputMode('manual')} className={`px-4 py-2 rounded text-sm ${inputMode==='manual'?'btn-primary':'btn-ghost'}`}>✏️ Manuell</button>
                  <button onClick={() => setInputMode('upload')} className={`px-4 py-2 rounded text-sm ${inputMode==='upload'?'btn-primary':'btn-ghost'}`}>📄 CSV/TXT</button>
                </div>
                {inputMode === 'manual' && <ManualInput onSave={saveManual} />}
                {inputMode === 'upload' && (
                  <div className="space-y-4">
                    <p className="text-sm text-gray-400">CSV (date,open,high,low,close,volume) oder TXT (Buchseite → KI extrahiert)</p>
                    <input type="file" accept=".csv,.txt" onChange={handleUpload} className="w-full" />
                    {uploading && <p className="text-sky-400 text-sm">⏳ KI extrahiert Daten...</p>}
                    {uploadResult && (
                      <div className="bg-green-900 bg-opacity-30 border border-green-700 rounded p-3 text-sm">
                        <p className="font-bold text-green-400">✓ {uploadResult.extracted?.data?.length || 0} Datenpunkte</p>
                        <button onClick={() => setTab('chart')} className="btn-primary px-3 py-1 rounded text-xs mt-2">→ Chart erstellen</button>
                      </div>
                    )}
                  </div>
                )}
              </div>
            </div>
            <div>
              <h3 className="font-bold mb-3 text-sm text-gray-400">Datasets</h3>
              <div className="space-y-2">
                {datasets.map(ds => (
                  <div key={ds.id} onClick={() => setSelDs(ds)}
                    className={`dark-card rounded p-3 cursor-pointer transition ${selDs?.id===ds.id?'border-sky-500':'hover:border-slate-500'}`}>
                    <div className="flex justify-between">
                      <div>
                        <p className="font-semibold text-sm">{ds.name}</p>
                        <p className="text-xs text-gray-500">{ds.data?.data?.length||0} Punkte</p>
                      </div>
                      <button onClick={e=>{e.stopPropagation();delDs(ds.id);}} className="text-red-500 text-xs">✕</button>
                    </div>
                  </div>
                ))}
              </div>
              {selDs && <button onClick={()=>setTab('chart')} className="btn-primary w-full py-2 rounded mt-4 text-sm">→ Chart erstellen</button>}
            </div>
          </div>
        )}

        {tab === 'chart' && (
          selDs
            ? <div>
                <div className="flex items-center gap-4 mb-4">
                  <span className="text-sm text-gray-400">Dataset:</span>
                  <select value={selDs.id} onChange={e => setSelDs(datasets.find(d => d.id === e.target.value))} className="text-sm">
                    {datasets.map(d => <option key={d.id} value={d.id}>{d.name}</option>)}
                  </select>
                </div>
                <ChartBuilder dataset={selDs} />
              </div>
            : <div className="text-center py-20">
                <p className="text-gray-400 mb-4">Zuerst Dataset anlegen</p>
                <button onClick={() => setTab('data')} className="btn-primary px-6 py-2 rounded">→ Daten eingeben</button>
              </div>
        )}

        {tab === 'word' && <WordExportTab pid={pid} />}
        {tab === 'pipeline' && <AiPipelineTab />}
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<AppWithWord />);

// ======== KI-PIPELINE TAB ========
function AiPipelineTab() {
  const [step, setStep] = useState(1);
  const [docxFile, setDocxFile] = useState(null);
  const [docxId, setDocxId] = useState(null);
  const [pageFrom, setPageFrom] = useState(1);
  const [pageTo, setPageTo] = useState(5);
  const [insertPage, setInsertPage] = useState(7);
  const [insertParagraph, setInsertParagraph] = useState(3);
  const [suggestions, setSuggestions] = useState([]);
  const [kontext, setKontext] = useState('');
  const [chosenChart, setChosenChart] = useState(null);
  const [chartConfig, setChartConfig] = useState(null);
  const [dataResult, setDataResult] = useState(null);
  const [caption, setCaption] = useState('');
  const [figureNumber, setFigureNumber] = useState(1);
  const [widthCm, setWidthCm] = useState(14);
  const [heightCm, setHeightCm] = useState(9);
  const [loading, setLoading] = useState(false);
  const [loadingMsg, setLoadingMsg] = useState('');
  const chartRef = useRef(null);

  async function analyzePages() {
    if (!docxFile) return alert('Bitte DOCX hochladen');
    setLoading(true); setLoadingMsg('KI analysiert Seiten ' + pageFrom + '-' + pageTo + '...');
    const fd = new FormData();
    fd.append('docx', docxFile);
    fd.append('pageFrom', pageFrom);
    fd.append('pageTo', pageTo);
    const r = await fetch('/api/pipeline/analyze', { method: 'POST', body: fd }).then(x => x.json());
    if (r.error) { alert('Fehler: ' + r.error); setLoading(false); return; }
    setDocxId(r.docxId);
    setSuggestions(r.suggestions?.vorschlaege || []);
    setKontext(r.suggestions?.kontext || '');
    setLoading(false);
    setStep(2);
  }

  async function chooseChart(chartType, chartTitel) {
    setChosenChart(chartType);
    setCaption(chartTitel || chartType);
    setLoading(true); setLoadingMsg('Extrahiere Daten + berechne Indikatoren...');
    const r = await fetch('/api/pipeline/extract', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ docxId, pageFrom, pageTo, chartType, insertPage, insertParagraph, caption, figureNumber })
    }).then(x => x.json());
    if (r.error) { alert('Fehler: ' + r.error); setLoading(false); return; }
    setChartConfig(r.chartConfig);
    setDataResult(r.dataResult);
    setLoading(false);
    setStep(3);
    // Chart rendern
    setTimeout(() => {
      if (r.chartConfig && document.getElementById('pipelineChart')) {
        Plotly.newPlot('pipelineChart', r.chartConfig.traces, {
          ...r.chartConfig.layout,
          paper_bgcolor: '#1e293b',
          plot_bgcolor: '#0f172a',
          font: { color: '#e2e8f0', family: 'Arial' },
          xaxis: { gridcolor: '#334155' },
          yaxis: { gridcolor: '#334155' }
        }, { responsive: true });
      }
    }, 300);
  }

  async function exportAndInsert() {
    setLoading(true); setLoadingMsg('Exportiere Chart + füge in DOCX ein...');
    try {
      // Chart als PNG exportieren
      const imgData = await Plotly.toImage('pipelineChart', { format: 'png', width: 1920, height: heightCm * 100, scale: 2 });

      const r = await fetch('/api/pipeline/insert', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          docxId, imageBase64: imgData,
          insertParagraph, caption, figureNumber, widthCm, heightCm
        })
      });
      if (!r.ok) { const e = await r.json(); alert('Fehler: ' + e.error); setLoading(false); return; }
      const blob = await r.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a'); a.href = url; a.download = 'buch_mit_chart.docx'; a.click();
      URL.revokeObjectURL(url);
      setStep(4);
    } catch (e) { alert('Fehler: ' + e.message); }
    setLoading(false);
  }

  function reset() { setStep(1); setDocxFile(null); setDocxId(null); setSuggestions([]); setChartConfig(null); setDataResult(null); setChosenChart(null); }

  return (
    <div className="max-w-4xl space-y-6">
      <div className="flex items-center justify-between">
        <h2 className="text-xl font-bold accent">🤖 KI-Pipeline: Seiten → Chart → Word</h2>
        {step > 1 && <button onClick={reset} className="btn-ghost px-3 py-1 rounded text-sm">↺ Neu starten</button>}
      </div>

      {/* SCHRITT 1: DOCX + Parameter */}
      <div className={`dark-card rounded-lg p-5 ${step >= 1 ? '' : 'opacity-50'}`}>
        <h3 className="font-bold mb-4 flex items-center gap-2">
          <span className={`w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${step >= 1 ? 'bg-sky-500' : 'bg-slate-600'}`}>1</span>
          Buchkapitel hochladen + Anweisung geben
        </h3>

        <div className="space-y-4">
          <div>
            <label className="block text-xs text-gray-400 mb-1">DOCX hochladen</label>
            <input type="file" accept=".docx" onChange={e => setDocxFile(e.target.files[0])} className="w-full" />
            {docxFile && <p className="text-green-400 text-xs mt-1">✓ {docxFile.name}</p>}
          </div>

          <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
            <div>
              <label className="block text-xs text-gray-400 mb-1">Analysiere ab Seite</label>
              <input type="number" min="1" value={pageFrom} onChange={e => setPageFrom(parseInt(e.target.value)||1)} className="w-full" />
            </div>
            <div>
              <label className="block text-xs text-gray-400 mb-1">bis Seite</label>
              <input type="number" min="1" value={pageTo} onChange={e => setPageTo(parseInt(e.target.value)||1)} className="w-full" />
            </div>
            <div>
              <label className="block text-xs text-gray-400 mb-1">Einfügen auf Seite</label>
              <input type="number" min="1" value={insertPage} onChange={e => setInsertPage(parseInt(e.target.value)||1)} className="w-full" />
            </div>
            <div>
              <label className="block text-xs text-gray-400 mb-1">Nach Absatz Nr.</label>
              <input type="number" min="1" value={insertParagraph} onChange={e => setInsertParagraph(parseInt(e.target.value)||1)} className="w-full" />
            </div>
          </div>

          <div className="p-3 bg-sky-900 bg-opacity-30 border border-sky-700 rounded text-sm">
            <p className="text-sky-300">
              💬 Anweisung: <em>„Schau dir Seiten {pageFrom}–{pageTo} an, erstelle eine passende Grafik und füge sie auf Seite {insertPage} nach Absatz {insertParagraph} ein."</em>
            </p>
          </div>

          <button onClick={analyzePages} disabled={!docxFile || loading}
            className="btn-primary px-6 py-2 rounded disabled:opacity-50">
            {loading && step === 1 ? `⏳ ${loadingMsg}` : '🤖 KI analysiert Seiten'}
          </button>
        </div>
      </div>

      {/* SCHRITT 2: KI-Vorschläge */}
      {step >= 2 && (
        <div className="dark-card rounded-lg p-5">
          <h3 className="font-bold mb-4 flex items-center gap-2">
            <span className="w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold bg-sky-500">2</span>
            KI-Vorschläge – wähle einen Chart-Typ
          </h3>

          {kontext && (
            <div className="p-3 bg-slate-900 rounded text-sm text-gray-400 mb-4">
              <p className="font-semibold text-gray-300 mb-1">📖 KI-Zusammenfassung:</p>
              <p>{kontext}</p>
            </div>
          )}

          <div className="space-y-3">
            {suggestions.map((s, i) => (
              <div key={i} className={`p-4 rounded border cursor-pointer transition ${
                chosenChart === s.typ ? 'border-sky-400 bg-sky-900 bg-opacity-30' : 'dark-card hover:border-slate-500'
              }`} onClick={() => !loading && chooseChart(s.typ, s.titel)}>
                <div className="flex items-start justify-between">
                  <div>
                    <div className="flex items-center gap-2 mb-1">
                      <span className="text-xs bg-slate-700 px-2 py-0.5 rounded text-gray-300">
                        #{s.prioritaet}
                      </span>
                      <span className="font-bold text-sky-300">
                        {CHART_TYPES.find(c => c.id === s.typ)?.label || s.typ}
                      </span>
                    </div>
                    <p className="text-sm text-gray-400">{s.begruendung}</p>
                    <p className="text-xs text-gray-500 mt-1 italic">{s.titel}</p>
                  </div>
                  {chosenChart === s.typ && (
                    <span className="text-sky-400 text-lg">✓</span>
                  )}
                </div>
                {loading && chosenChart === s.typ && (
                  <p className="text-sky-400 text-xs mt-2">⏳ {loadingMsg}</p>
                )}
              </div>
            ))}
          </div>
        </div>
      )}

      {/* SCHRITT 3: Chart-Vorschau + Feintuning */}
      {step >= 3 && chartConfig && (
        <div className="dark-card rounded-lg p-5">
          <h3 className="font-bold mb-4 flex items-center gap-2">
            <span className="w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold bg-sky-500">3</span>
            Chart-Vorschau + Feintuning
          </h3>

          {dataResult && (
            <div className="mb-4 p-3 bg-green-900 bg-opacity-30 border border-green-700 rounded text-sm">
              <p className="text-green-400 font-bold">✓ Daten extrahiert</p>
              <p className="text-gray-400">Ticker: {dataResult.ticker || '?'} | {dataResult.data?.length || 0} Datenpunkte | {dataResult.hatDaten ? 'aus Text' : 'KI-Beispieldaten'}</p>
              {!dataResult.hatDaten && <p className="text-yellow-400 text-xs mt-1">⚠️ Keine konkreten Kursdaten im Text gefunden – KI hat realistische Beispieldaten generiert.</p>}
            </div>
          )}

          <div id="pipelineChart" className="rounded-lg mb-4" style={{minHeight:'400px'}}></div>

          <div className="grid md:grid-cols-2 gap-4 mb-4">
            <div>
              <label className="block text-xs text-gray-400 mb-1">Bildunterschrift</label>
              <input type="text" value={caption} onChange={e => setCaption(e.target.value)} className="w-full" />
            </div>
            <div>
              <label className="block text-xs text-gray-400 mb-1">Abbildungsnummer</label>
              <input type="number" min="1" value={figureNumber} onChange={e => setFigureNumber(parseInt(e.target.value))} className="w-full" />
            </div>
            <div>
              <label className="block text-xs text-gray-400 mb-1">Breite (cm)</label>
              <input type="number" min="4" max="20" step="0.5" value={widthCm} onChange={e => setWidthCm(parseFloat(e.target.value))} className="w-full" />
            </div>
            <div>
              <label className="block text-xs text-gray-400 mb-1">Höhe (cm)</label>
              <input type="number" min="3" max="15" step="0.5" value={heightCm} onChange={e => setHeightCm(parseFloat(e.target.value))} className="w-full" />
            </div>
          </div>

          <div className="p-3 bg-slate-900 rounded text-sm mb-4">
            <p className="text-gray-400">📍 Einfügeposition: Seite {insertPage}, nach Absatz {insertParagraph}</p>
            <p className="text-gray-400">📐 Größe: {widthCm} × {heightCm} cm | Abb. {figureNumber}: {caption}</p>
          </div>

          <button onClick={exportAndInsert} disabled={loading}
            className="btn-primary px-6 py-3 rounded font-bold text-lg disabled:opacity-50 w-full">
            {loading ? `⏳ ${loadingMsg}` : '📥 Chart einfügen + DOCX herunterladen'}
          </button>
        </div>
      )}

      {/* SCHRITT 4: Fertig */}
      {step >= 4 && (
        <div className="dark-card rounded-lg p-8 text-center border border-green-700">
          <p className="text-4xl mb-4">✅</p>
          <h3 className="text-xl font-bold text-green-400 mb-2">Fertig!</h3>
          <p className="text-gray-400 mb-4">
            Die DOCX wurde mit dem Chart auf Seite {insertPage}, Absatz {insertParagraph} heruntergeladen.
          </p>
          <p className="text-sm text-gray-500">Abb. {figureNumber}: {caption}</p>
          <button onClick={reset} className="btn-primary px-6 py-2 rounded mt-6">
            Nächste Grafik erstellen
          </button>
        </div>
      )}
    </div>
  );
}
