<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Stock Prediction Engine</title>
    <script src="https://cdn.plot.ly/plotly-2.32.0.min.js"></script>
    <style>
        :root {
            --bg: #0d1117; --card: #161b22; --border: #30363d;
            --text: #c9d1d9; --muted: #8b949e; --accent: #58a6ff;
            --green: #3fb950; --red: #f85149; --yellow: #d29922;
        }
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--text); }
        .container { max-width: 1440px; margin: 0 auto; padding: 20px; }
        header { display: flex; justify-content: space-between; align-items: center; padding: 16px 0; border-bottom: 1px solid var(--border); margin-bottom: 20px; }
        header h1 { font-size: 1.4rem; }
        .badge { background: var(--border); padding: 4px 10px; border-radius: 12px; font-size: 0.75rem; }
        .badge.green { background: #1a3a2a; color: var(--green); }
        .badge.red { background: #3a1a1a; color: var(--red); }
        .controls { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; align-items: center; }
        button { background: var(--card); color: var(--text); border: 1px solid var(--border); padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 0.85rem; transition: all 0.15s; }
        button:hover { border-color: var(--accent); color: var(--accent); }
        button.primary { background: #1f3a5f; border-color: var(--accent); color: var(--accent); }
        button.primary:hover { background: #2a4a6f; }
        select { background: var(--card); color: var(--text); border: 1px solid var(--border); padding: 8px 12px; border-radius: 6px; font-size: 0.85rem; }
        .ticker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; margin-bottom: 24px; }
        .ticker-card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 16px; transition: border-color 0.15s; }
        .ticker-card:hover { border-color: var(--accent); }
        .ticker-card h3 { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
        .ticker-card .price { font-size: 1.5rem; font-weight: 600; }
        .ticker-card .meta { color: var(--muted); font-size: 0.8rem; margin-top: 4px; }
        .prediction { margin-top: 12px; padding: 10px; border-radius: 6px; font-size: 0.85rem; }
        .prediction.up { background: #1a3a2a; border-left: 3px solid var(--green); }
        .prediction.down { background: #3a1a1a; border-left: 3px solid var(--red); }
        .prediction.neutral { background: #2a2a1a; border-left: 3px solid var(--yellow); }
        .prediction .dir { font-weight: 600; text-transform: uppercase; font-size: 0.9rem; }
        .prediction .conf { color: var(--muted); font-size: 0.75rem; }
        .chart-section { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 20px; margin-bottom: 20px; }
        .chart-section h2 { font-size: 1.1rem; margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; }
        .alerts-section { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 20px; margin-bottom: 20px; }
        .alert-item { padding: 10px 14px; margin-bottom: 8px; border-radius: 6px; font-size: 0.85rem; display: flex; justify-content: space-between; align-items: center; }
        .alert-item.high { background: #3a1a1a; border-left: 3px solid var(--red); }
        .alert-item.medium { background: #2a2a1a; border-left: 3px solid var(--yellow); }
        .alert-item.low { background: #1a2a3a; border-left: 3px solid var(--accent); }
        .alert-item .time { color: var(--muted); font-size: 0.75rem; }
        .stats-row { display: flex; gap: 20px; margin-bottom: 20px; flex-wrap: wrap; }
        .stat-box { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 16px 24px; flex: 1; min-width: 150px; text-align: center; }
        .stat-box .value { font-size: 1.6rem; font-weight: 700; }
        .stat-box .label { color: var(--muted); font-size: 0.75rem; margin-top: 4px; text-transform: uppercase; }
        .loading { text-align: center; padding: 40px; color: var(--muted); }
        .spinner { display: inline-block; width: 24px; height: 24px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; }
        @keyframes spin { to { transform: rotate(360deg); } }
        .progress { width: 100%; height: 4px; background: var(--border); border-radius: 2px; margin-top: 8px; }
        .progress-bar { height: 100%; background: var(--accent); border-radius: 2px; transition: width 0.3s; }
        .feature-importance { margin-top: 12px; }
        .feature-bar { display: flex; align-items: center; margin-bottom: 4px; font-size: 0.75rem; }
        .feature-bar .name { width: 140px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .feature-bar .bar { flex: 1; height: 6px; background: var(--border); border-radius: 3px; margin: 0 8px; }
        .feature-bar .bar-fill { height: 100%; background: var(--accent); border-radius: 3px; }
        .feature-bar .val { width: 40px; text-align: right; color: var(--muted); }
        #mainChart { width: 100%; }
        #indicatorChart { width: 100%; }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>📈 Stock Prediction Engine</h1>
            <div style="display:flex;gap:10px;align-items:center;">
                <span class="badge" id="statusBadge">Connecting...</span>
                <span class="badge" id="lastUpdate">--</span>
                <button onclick="refreshAll()" title="Refresh">↻</button>
            </div>
        </header>

        <div class="stats-row" id="statsRow">
            <div class="stat-box"><div class="value" id="statTickers">--</div><div class="label">Tickers</div></div>
            <div class="stat-box"><div class="value" id="statModels">--</div><div class="label">Models Trained</div></div>
            <div class="stat-box"><div class="value" id="statAlerts">--</div><div class="label">Active Alerts</div></div>
            <div class="stat-box"><div class="value" id="statAvgAcc">--</div><div class="label">Avg Accuracy</div></div>
        </div>

        <div class="controls">
            <select id="tickerSelect" onchange="onTickerChange()">
                <option value="">Select Ticker...</option>
            </select>
            <button class="primary" onclick="trainSelected()">🧠 Train Model</button>
            <button onclick="trainAll()">Train All</button>
            <button onclick="fetchData()">↻ Fetch Data</button>
            <button onclick="loadAlerts()">🔔 Alerts</button>
        </div>

        <div id="tickerGrid" class="ticker-grid"></div>

        <div class="chart-section">
            <h2>Price Chart <span id="chartTicker" style="color:var(--accent);font-size:0.9rem;"></span></h2>
            <div id="mainChart"></div>
        </div>

        <div class="chart-section">
            <h2>Technical Indicators</h2>
            <div id="indicatorChart"></div>
        </div>

        <div class="chart-section" id="modelSection" style="display:none;">
            <h2>Model Info <span id="modelTicker" style="color:var(--accent);font-size:0.9rem;"></span></h2>
            <div id="modelMetrics"></div>
            <div class="feature-importance" id="featureImportance"></div>
        </div>

        <div class="alerts-section" id="alertsSection" style="display:none;">
            <h2 style="margin-bottom:12px;">🔔 Active Alerts</h2>
            <div id="alertsList"></div>
        </div>
    </div>

    <script>
        const API = window.location.origin;
        let tickerData = {};
        let dashboardData = null;

        async function api(path) {
            const r = await fetch(API + path);
            if (!r.ok) throw new Error(`${r.status}: ${path}`);
            return r.json();
        }

        async function refreshAll() {
            await loadDashboard();
            await loadAlerts();
        }

        async function loadDashboard() {
            try {
                document.getElementById('statusBadge').textContent = 'Loading...';
                document.getElementById('statusBadge').className = 'badge';
                
                dashboardData = await api('/api/dashboard');
                
                const tickers = dashboardData.tickers;
                const select = document.getElementById('tickerSelect');
                const grid = document.getElementById('tickerGrid');
                
                // Update stats
                const trained = tickers.filter(t => t.has_model).length;
                const accs = tickers.filter(t => t.latest && t.prediction && t.prediction.model_accuracy)
                    .map(t => t.prediction.model_accuracy);
                const avgAcc = accs.length ? (accs.reduce((a,b) => a+b, 0) / accs.length) : 0;
                
                document.getElementById('statTickers').textContent = tickers.length;
                document.getElementById('statModels').textContent = trained;
                document.getElementById('statAvgAcc').textContent = avgAcc ? (avgAcc * 100).toFixed(1) + '%' : '--';
                document.getElementById('lastUpdate').textContent = new Date(dashboardData.updated_at).toLocaleTimeString();
                document.getElementById('statusBadge').textContent = 'Online';
                document.getElementById('statusBadge').className = 'badge green';
                
                // Populate select
                select.innerHTML = '<option value="">Select Ticker...</option>';
                tickers.forEach(t => {
                    const opt = document.createElement('option');
                    opt.value = t.ticker;
                    opt.textContent = t.ticker;
                    select.appendChild(opt);
                });
                
                // Build ticker cards
                grid.innerHTML = '';
                tickers.forEach(t => {
                    const card = document.createElement('div');
                    card.className = 'ticker-card';
                    card.onclick = () => { select.value = t.ticker; onTickerChange(); };
                    card.style.cursor = 'pointer';
                    
                    let predHtml = '';
                    if (t.prediction) {
                        const p = t.prediction;
                        const dirClass = p.direction || 'neutral';
                        predHtml = `<div class="prediction ${dirClass}">
                            <div class="dir">${p.direction || 'neutral'} ${p.pct_change ? ' (' + (p.pct_change > 0 ? '+' : '') + p.pct_change.toFixed(2) + '%)' : ''}</div>
                            <div class="conf">Confidence: ${(p.confidence * 100).toFixed(1)}% | Accuracy: ${p.model_accuracy ? (p.model_accuracy * 100).toFixed(1) + '%' : '--'}</div>
                        </div>`;
                    } else if (t.has_model) {
                        predHtml = '<div class="prediction neutral"><div class="dir">Model Ready</div><div class="conf">Select to see prediction</div></div>';
                    } else {
                        predHtml = '<div class="prediction neutral"><div class="dir">Not Trained</div><div class="conf">Click "Train Model" to start</div></div>';
                    }
                    
                    card.innerHTML = `
                        <h3>${t.ticker} ${t.has_model ? '<span class="badge green">✓</span>' : '<span class="badge">○</span>'}</h3>
                        <div class="price">$${t.latest ? t.latest.close?.toFixed(2) || '--' : '--'}</div>
                        <div class="meta">${t.latest ? t.latest.date?.split('T')[0] || '' : ''}</div>
                        ${predHtml}
                    `;
                    grid.appendChild(card);
                });
            } catch (e) {
                document.getElementById('statusBadge').textContent = 'Error';
                document.getElementById('statusBadge').className = 'badge red';
                console.error(e);
            }
        }

        async function onTickerChange() {
            const ticker = document.getElementById('tickerSelect').value;
            if (!ticker) return;
            await loadChart(ticker);
            await loadModel(ticker);
        }

        async function loadChart(ticker) {
            try {
                document.getElementById('chartTicker').textContent = ticker;
                const data = await api(`/api/data/${ticker}?limit=200`);
                const rows = data.data;
                
                const dates = rows.map(r => r.Date);
                const closes = rows.map(r => r.Close);
                const volumes = rows.map(r => r.Volume);
                const sma20 = rows.map(r => r.SMA_20);
                const ema12 = rows.map(r => r.EMA_12);
                const bbUpper = rows.map(r => r.BB_upper);
                const bbLower = rows.map(r => r.BB_lower);
                
                // Price chart
                const traces = [
                    {
                        x: dates, y: closes, type: 'candlestick',
                        open: rows.map(r => r.Open), high: rows.map(r => r.High),
                        low: rows.map(r => r.Low), close: closes,
                        name: 'Price', increasing: {line: {color: '#3fb950'}},
                        decreasing: {line: {color: '#f85149'}},
                    },
                    { x: dates, y: sma20, type: 'scatter', mode: 'lines', name: 'SMA 20',
                      line: {color: '#d29922', width: 1.5}, yaxis: 'y' },
                    { x: dates, y: ema12, type: 'scatter', mode: 'lines', name: 'EMA 12',
                      line: {color: '#58a6ff', width: 1.5}, yaxis: 'y' },
                    { x: [...dates, ...dates.reverse()], y: [...bbUpper, ...bbLower.reverse()],
                      fill: 'toself', fillcolor: 'rgba(88,166,255,0.1)', line: {color: 'transparent'},
                      name: 'BB', yaxis: 'y', showlegend: true },
                    { x: dates, y: volumes, type: 'bar', name: 'Volume', yaxis: 'y2',
                      marker: {color: volumes.map((v, i) => closes[i] >= (closes[i-1] || closes[i]) ? '#3fb950' : '#f85149')} },
                ];
                
                Plotly.newPlot('mainChart', traces, {
                    paper_bgcolor: '#161b22', plot_bgcolor: '#161b22',
                    font: {color: '#8b949e', size: 11},
                    margin: {t: 30, r: 30, b: 40, l: 60},
                    xaxis: {gridcolor: '#30363d', rangeslider: {visible: false}},
                    yaxis: {gridcolor: '#30363d', domain: [0.35, 1]},
                    yaxis2: {gridcolor: '#30363d', domain: [0, 0.25]},
                    showlegend: true, legend: {bgcolor: 'transparent', font: {size: 10}},
                }, {responsive: true, displayModeBar: false});
                
                // Indicator chart
                const rsi = rows.map(r => r.RSI);
                const macdHist = rows.map(r => r.MACD_histogram);
                
                const indTraces = [
                    { x: dates, y: rsi, type: 'scatter', mode: 'lines', name: 'RSI',
                      line: {color: '#d29922', width: 1.5}, yaxis: 'y' },
                    { x: dates, y: macdHist, type: 'bar', name: 'MACD Hist', yaxis: 'y2',
                      marker: {color: macdHist.map(v => v >= 0 ? '#3fb950' : '#f85149')} },
                ];
                
                Plotly.newPlot('indicatorChart', indTraces, {
                    paper_bgcolor: '#161b22', plot_bgcolor: '#161b22',
                    font: {color: '#8b949e', size: 11},
                    margin: {t: 30, r: 30, b: 40, l: 60},
                    xaxis: {gridcolor: '#30363d'},
                    yaxis: {gridcolor: '#30363d', domain: [0.55, 1], range: [0, 100]},
                    yaxis2: {gridcolor: '#30363d', domain: [0, 0.45]},
                    showlegend: true, legend: {bgcolor: 'transparent', font: {size: 10}},
                    shapes: [
                        {type: 'line', y0: 70, y1: 70, x0: 0, x1: 1, xref: 'paper', line: {color: '#f85149', width: 1, dash: 'dot'}, yaxis: 'y'},
                        {type: 'line', y0: 30, y1: 30, x0: 0, x1: 1, xref: 'paper', line: {color: '#3fb950', width: 1, dash: 'dot'}, yaxis: 'y'},
                    ],
                }, {responsive: true, displayModeBar: false});
                
            } catch (e) {
                console.error('Chart error:', e);
            }
        }

        async function loadModel(ticker) {
            try {
                const info = await api(`/api/model/${ticker}`);
                document.getElementById('modelSection').style.display = 'block';
                document.getElementById('modelTicker').textContent = ticker;
                
                const m = info.metrics;
                document.getElementById('modelMetrics').innerHTML = `
                    <div class="stats-row">
                        <div class="stat-box"><div class="value">${(m.classification.accuracy * 100).toFixed(1)}%</div><div class="label">Accuracy</div></div>
                        <div class="stat-box"><div class="value">${(m.classification.precision * 100).toFixed(1)}%</div><div class="label">Precision</div></div>
                        <div class="stat-box"><div class="value">${(m.classification.recall * 100).toFixed(1)}%</div><div class="label">Recall</div></div>
                        <div class="stat-box"><div class="value">${(m.classification.f1 * 100).toFixed(1)}%</div><div class="label">F1 Score</div></div>
                        <div class="stat-box"><div class="value">${m.regression.r2.toFixed(3)}</div><div class="label">R²</div></div>
                        <div class="stat-box"><div class="value">${m.train_size}</div><div class="label">Training Bars</div></div>
                    </div>
                    <div style="color:var(--muted);font-size:0.75rem;">Trained: ${info.trained_at} | Features: ${info.feature_count} | MAE: ${m.regression.mae.toFixed(4)}% | RMSE: ${m.regression.rmse.toFixed(4)}%</div>
                `;
                
                // Feature importance
                const impDiv = document.getElementById('featureImportance');
                const maxImp = info.feature_importance[0]?.importance || 1;
                impDiv.innerHTML = '<h3 style="margin:16px 0 8px;font-size:0.9rem;">Feature Importance</h3>' +
                    info.feature_importance.map(f => `
                        <div class="feature-bar">
                            <span class="name">${f.feature}</span>
                            <div class="bar"><div class="bar-fill" style="width:${(f.importance / maxImp * 100).toFixed(0)}%"></div></div>
                            <span class="val">${f.importance.toFixed(3)}</span>
                        </div>
                    `).join('');
            } catch (e) {
                document.getElementById('modelSection').style.display = 'none';
            }
        }

        async function loadAlerts() {
            try {
                const data = await api('/api/alerts');
                const section = document.getElementById('alertsSection');
                const list = document.getElementById('alertsList');
                document.getElementById('statAlerts').textContent = data.count;
                
                if (data.count === 0) {
                    section.style.display = 'none';
                    return;
                }
                
                section.style.display = 'block';
                list.innerHTML = data.alerts.map(a => `
                    <div class="alert-item ${a.severity}">
                        <div>
                            <strong>${a.ticker}</strong> — ${a.message}
                            ${a.type === 'prediction' ? `<span class="badge ${a.direction === 'up' ? 'green' : 'red'}">${a.direction} ${(a.confidence * 100).toFixed(0)}%</span>` : ''}
                        </div>
                        <div class="time">${a.timestamp?.split('T')[1] || ''}</div>
                    </div>
                `).join('');
            } catch (e) {
                console.error('Alert error:', e);
            }
        }

        async function trainSelected() {
            const ticker = document.getElementById('tickerSelect').value;
            if (!ticker) return alert('Select a ticker first');
            await trainTicker(ticker);
        }

        async function trainTicker(ticker) {
            try {
                const btn = event.target;
                btn.textContent = 'Training...';
                btn.disabled = true;
                const result = await api(`/api/train/${ticker}`);
                btn.textContent = `✓ ${result.metrics.classification.accuracy.toFixed(1)}`;
                setTimeout(() => { btn.textContent = '🧠 Train Model'; btn.disabled = false; }, 2000);
                await loadDashboard();
                if (document.getElementById('tickerSelect').value === ticker) {
                    await loadChart(ticker);
                    await loadModel(ticker);
                }
            } catch (e) {
                event.target.textContent = '✗ Error';
                setTimeout(() => { event.target.textContent = '🧠 Train Model'; }, 2000);
                alert('Training failed: ' + e.message);
            }
        }

        async function trainAll() {
            try {
                event.target.textContent = 'Training all...';
                event.target.disabled = true;
                const result = await api('/api/train_all');
                const ok = result.results.filter(r => r.status === 'ok').length;
                event.target.textContent = `✓ ${ok}/${result.results.length}`;
                setTimeout(() => { event.target.textContent = 'Train All'; event.target.disabled = false; }, 3000);
                await loadDashboard();
            } catch (e) {
                alert('Train all failed: ' + e.message);
                event.target.textContent = 'Train All';
                event.target.disabled = false;
            }
        }

        async function fetchData() {
            try {
                event.target.textContent = 'Fetching...';
                event.target.disabled = true;
                const data = await api('/api/tickers');
                event.target.textContent = `✓ ${data.tickers.length}`;
                setTimeout(() => { event.target.textContent = '↻ Fetch Data'; event.target.disabled = false; }, 2000);
            } catch (e) {
                event.target.textContent = '↻ Fetch Data';
                event.target.disabled = false;
            }
        }

        // Init
        refreshAll();
        
        // Auto-refresh every 5 minutes
        setInterval(refreshAll, 300000);
    </script>
</body>
</html>