{% extends "base.html" %}
{% block title %}LLM Trainer - AUTARCH{% endblock %}

{% block content %}
<div class="page-header" style="display:flex;align-items:center;gap:1rem;flex-wrap:wrap">
    <div>
        <h1>LLM Trainer</h1>
        <p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
            Fine-tune language models on the AUTARCH codebase. Generate datasets, train LoRA adapters, convert to GGUF.
        </p>
    </div>
    <a href="{{ url_for('analyze.index') }}" class="btn btn-sm" style="margin-left:auto">&larr; Analyze</a>
</div>

<!-- Tab Bar -->
<div class="tab-bar">
    <button class="tab active" data-tab-group="trainer" data-tab="dataset" onclick="showTab('trainer','dataset')">Dataset</button>
    <button class="tab" data-tab-group="trainer" data-tab="training" onclick="showTab('trainer','training')">Training</button>
    <button class="tab" data-tab-group="trainer" data-tab="convert" onclick="showTab('trainer','convert')">Convert</button>
    <button class="tab" data-tab-group="trainer" data-tab="evaluate" onclick="showTab('trainer','evaluate')">Evaluate</button>
</div>

<!-- ==================== DATASET TAB ==================== -->
<div class="tab-content active" data-tab-group="trainer" data-tab="dataset">
<div class="section">
    <h2>Codebase Scan</h2>
    <div class="tool-actions">
        <button id="btn-scan" class="btn btn-primary" onclick="trScanCodebase()">Scan Codebase</button>
    </div>
    <div id="scan-result" style="margin-top:12px"></div>
</div>

<div class="section">
    <h2>Generate Training Dataset</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Extracts code, architecture Q&A, and module creation examples from the AUTARCH codebase into JSONL training data.
    </p>
    <div class="form-row" style="margin-bottom:12px">
        <div class="form-group">
            <label>Format</label>
            <select id="ds-format">
                <option value="sharegpt">ShareGPT (conversations)</option>
                <option value="instruction">Alpaca (instruction/output)</option>
            </select>
        </div>
    </div>
    <div style="margin-bottom:12px">
        <label><input type="checkbox" id="ds-source" checked> Include source code understanding</label><br>
        <label><input type="checkbox" id="ds-qa" checked> Include architecture Q&A</label><br>
        <label><input type="checkbox" id="ds-modules" checked> Include module creation examples</label>
    </div>
    <div class="tool-actions">
        <button id="btn-generate" class="btn btn-primary" onclick="trGenerateDataset()">Generate Dataset</button>
    </div>
    <pre class="output-panel" id="gen-result" style="margin-top:12px;min-height:0"></pre>
</div>

<div class="section">
    <h2>Saved Datasets</h2>
    <div class="tool-actions">
        <button class="btn btn-small" onclick="trListDatasets()">Refresh</button>
    </div>
    <div id="datasets-list" style="margin-top:12px">
        <p class="empty-state">Click "Refresh" to load datasets.</p>
    </div>
</div>
</div>

<!-- ==================== TRAINING TAB ==================== -->
<div class="tab-content" data-tab-group="trainer" data-tab="training">
<div class="section">
    <h2>LoRA Fine-Tuning</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Fine-tune a base model with LoRA adapters on your generated dataset. Requires a HuggingFace model ID or local path.
    </p>

    <div class="form-row" style="margin-bottom:8px">
        <div class="form-group" style="flex:2">
            <label>Base Model (local path)</label>
            <div class="input-row">
                <input type="text" id="tr-base-model" placeholder="Click Browse or paste a local model path...">
                <button class="btn btn-small" onclick="trOpenBrowser()">Browse</button>
            </div>
        </div>
        <div class="form-group" style="flex:1">
            <label>Dataset</label>
            <select id="tr-dataset">
                <option value="">Select dataset...</option>
            </select>
        </div>
    </div>

    <!-- File Browser Modal -->
    <div id="model-browser-overlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:1000;display:none;align-items:center;justify-content:center">
        <div style="background:var(--bg-secondary);border:1px solid var(--border);border-radius:8px;width:90%;max-width:700px;max-height:80vh;display:flex;flex-direction:column;padding:16px">
            <div style="display:flex;align-items:center;gap:8px;margin-bottom:12px">
                <h3 style="margin:0;flex:1">Select Base Model</h3>
                <button class="btn btn-small" onclick="trCloseBrowser()">Close</button>
            </div>
            <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
                <button class="btn btn-small" onclick="trBrowseUp()" title="Parent directory">&uarr; Up</button>
                <code id="browser-path" style="flex:1;font-size:0.78rem;color:var(--text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></code>
            </div>
            <div id="browser-entries" style="flex:1;overflow-y:auto;border:1px solid var(--border);border-radius:4px;font-size:0.82rem"></div>
            <p style="font-size:0.72rem;color:var(--text-muted);margin:8px 0 0">Select a directory containing config.json + model weights, or navigate to find your model.</p>
        </div>
    </div>

    <details style="margin-bottom:12px">
        <summary style="cursor:pointer;font-size:0.85rem;color:var(--accent)">Advanced Settings</summary>
        <div class="form-row" style="margin-top:8px">
            <div class="form-group">
                <label>LoRA Rank (r)</label>
                <input type="number" id="tr-lora-r" value="16" min="4" max="128" style="max-width:80px">
            </div>
            <div class="form-group">
                <label>LoRA Alpha</label>
                <input type="number" id="tr-lora-alpha" value="32" min="8" max="256" style="max-width:80px">
            </div>
            <div class="form-group">
                <label>Dropout</label>
                <input type="number" id="tr-dropout" value="0.05" step="0.01" min="0" max="0.5" style="max-width:80px">
            </div>
            <div class="form-group">
                <label>Epochs</label>
                <input type="number" id="tr-epochs" value="3" min="1" max="20" style="max-width:80px">
            </div>
        </div>
        <div class="form-row">
            <div class="form-group">
                <label>Batch Size</label>
                <input type="number" id="tr-batch" value="4" min="1" max="32" style="max-width:80px">
            </div>
            <div class="form-group">
                <label>Grad Accum Steps</label>
                <input type="number" id="tr-grad-accum" value="4" min="1" max="32" style="max-width:80px">
            </div>
            <div class="form-group">
                <label>Learning Rate</label>
                <input type="text" id="tr-lr" value="2e-4" style="max-width:100px">
            </div>
            <div class="form-group">
                <label>Max Seq Length</label>
                <input type="number" id="tr-seq-len" value="2048" min="512" max="8192" style="max-width:100px">
            </div>
        </div>
        <div style="margin-top:4px">
            <label><input type="checkbox" id="tr-4bit" checked> Use 4-bit quantization (QLoRA)</label><br>
            <label><input type="checkbox" id="tr-unsloth"> Use Unsloth (faster, if installed)</label>
        </div>
    </details>

    <div class="tool-actions">
        <button id="btn-train-start" class="btn btn-primary" onclick="trStartTraining()">Start Training</button>
        <button id="btn-train-stop" class="btn btn-danger" onclick="trStopTraining()" style="display:none">Stop Training</button>
    </div>

    <div id="training-status" style="margin-top:12px">
        <div class="stats-grid" style="grid-template-columns:repeat(auto-fit,minmax(120px,1fr))">
            <div class="stat-card">
                <div class="stat-label">Phase</div>
                <div class="stat-value small" id="tr-phase">Idle</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Progress</div>
                <div class="stat-value small" id="tr-progress">0%</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Status</div>
                <div class="stat-value small" id="tr-message">Ready</div>
            </div>
        </div>
    </div>

    <h4 style="margin-top:16px">Training Log</h4>
    <pre class="output-panel scrollable" id="training-log" style="max-height:300px;font-size:0.75rem">Training log will appear here...</pre>
</div>
</div>

<!-- ==================== CONVERT TAB ==================== -->
<div class="tab-content" data-tab-group="trainer" data-tab="convert">
<div class="section">
    <h2>GGUF Conversion</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Merge a trained LoRA adapter with its base model and convert to GGUF format for local inference.
    </p>

    <h4>Saved LoRA Adapters</h4>
    <div class="tool-actions">
        <button class="btn btn-small" onclick="trListAdapters()">Refresh Adapters</button>
    </div>
    <div id="adapters-list" style="margin-top:8px">
        <p class="empty-state">Click "Refresh" to load adapters.</p>
    </div>

    <h4 style="margin-top:16px">Convert to GGUF</h4>
    <div class="form-row" style="margin-bottom:12px">
        <div class="form-group" style="flex:2">
            <label>Adapter Path</label>
            <input type="text" id="cv-adapter" placeholder="Path to LoRA adapter directory">
        </div>
        <div class="form-group">
            <label>Output Name</label>
            <input type="text" id="cv-output" placeholder="e.g., Hal_v3" value="Hal_v3">
        </div>
        <div class="form-group">
            <label>Quantization</label>
            <select id="cv-quant">
                <option value="Q4_K_M">Q4_K_M (small, fast)</option>
                <option value="Q5_K_M" selected>Q5_K_M (balanced)</option>
                <option value="Q6_K">Q6_K (quality)</option>
                <option value="Q8_0">Q8_0 (high quality)</option>
                <option value="F16">F16 (unquantized)</option>
            </select>
        </div>
    </div>
    <div class="tool-actions">
        <button id="btn-convert" class="btn btn-primary" onclick="trConvert()">Merge & Convert</button>
    </div>
    <pre class="output-panel" id="convert-result" style="margin-top:12px;min-height:0"></pre>

    <h4 style="margin-top:16px">Available GGUF Models</h4>
    <div class="tool-actions">
        <button class="btn btn-small" onclick="trListModels()">Refresh Models</button>
    </div>
    <div id="models-list" style="margin-top:8px">
        <p class="empty-state">Click "Refresh" to load models.</p>
    </div>
</div>
</div>

<!-- ==================== EVALUATE TAB ==================== -->
<div class="tab-content" data-tab-group="trainer" data-tab="evaluate">
<div class="section">
    <h2>Model Evaluation</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Test a GGUF model with sample prompts to verify it learned the AUTARCH codebase.
    </p>

    <div class="form-row" style="margin-bottom:12px">
        <div class="form-group" style="flex:2">
            <label>Model Path</label>
            <select id="ev-model">
                <option value="">Select model...</option>
            </select>
        </div>
    </div>

    <h4>Test Prompts</h4>
    <div id="eval-prompts">
        <div class="input-row" style="margin-bottom:4px">
            <input type="text" class="eval-prompt" value="What is AUTARCH?" style="flex:1">
        </div>
        <div class="input-row" style="margin-bottom:4px">
            <input type="text" class="eval-prompt" value="How do I create a new defense module?" style="flex:1">
        </div>
        <div class="input-row" style="margin-bottom:4px">
            <input type="text" class="eval-prompt" value="What module categories does AUTARCH support?" style="flex:1">
        </div>
        <div class="input-row" style="margin-bottom:4px">
            <input type="text" class="eval-prompt" value="Create a module that scans for open ports on localhost." style="flex:1">
        </div>
    </div>
    <button class="btn btn-small" onclick="trAddPrompt()" style="margin-top:4px">+ Add Prompt</button>

    <div class="tool-actions" style="margin-top:12px">
        <button id="btn-evaluate" class="btn btn-primary" onclick="trEvaluate()">Run Evaluation</button>
    </div>

    <div id="eval-results" style="margin-top:12px"></div>
</div>
</div>

<script>
/* ── LLM Trainer ── */
var _trPollInterval = null;

function trScanCodebase() {
    var btn = document.getElementById('btn-scan');
    setLoading(btn, true);
    postJSON('/llm-trainer/scan', {}).then(function(data) {
        setLoading(btn, false);
        var inv = data.inventory || {};
        var html = '<table class="data-table" style="font-size:0.82rem"><thead><tr>'
            + '<th>Category</th><th>Files</th><th>Lines</th></tr></thead><tbody>';
        var cats = ['modules','core','routes','templates','configs','other'];
        cats.forEach(function(cat) {
            var files = inv[cat] || [];
            var lines = files.reduce(function(s,f){return s+f.lines},0);
            html += '<tr><td>' + cat + '</td><td>' + files.length + '</td><td>' + lines.toLocaleString() + '</td></tr>';
        });
        html += '<tr style="font-weight:bold"><td>Total</td><td>' + data.total_files
            + '</td><td>' + data.total_lines.toLocaleString() + '</td></tr>';
        html += '</tbody></table>';
        document.getElementById('scan-result').innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

function trGenerateDataset() {
    var btn = document.getElementById('btn-generate');
    setLoading(btn, true);
    postJSON('/llm-trainer/dataset/generate', {
        format: document.getElementById('ds-format').value,
        include_source: document.getElementById('ds-source').checked,
        include_qa: document.getElementById('ds-qa').checked,
        include_module_creation: document.getElementById('ds-modules').checked,
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            renderOutput('gen-result', 'Error: ' + data.error);
            return;
        }
        var lines = [
            'Dataset Generated!',
            '  File: ' + data.filename,
            '  Samples: ' + data.sample_count,
            '  Format: ' + data.format,
            '  Size: ' + (data.size_bytes / 1024).toFixed(1) + ' KB',
            '',
            'Preview (first sample):',
        ];
        if (data.preview && data.preview.length) {
            lines.push(JSON.stringify(data.preview[0], null, 2));
        }
        renderOutput('gen-result', lines.join('\n'));
        trListDatasets();
        trRefreshDatasetSelect();
    }).catch(function() { setLoading(btn, false); });
}

function trListDatasets() {
    fetchJSON('/llm-trainer/dataset/list').then(function(data) {
        var ds = data.datasets || [];
        var container = document.getElementById('datasets-list');
        if (!ds.length) {
            container.innerHTML = '<p class="empty-state">No datasets generated yet.</p>';
            return;
        }
        var html = '<table class="data-table" style="font-size:0.8rem"><thead><tr>'
            + '<th>File</th><th>Samples</th><th>Size</th><th>Created</th><th>Actions</th></tr></thead><tbody>';
        ds.forEach(function(d) {
            html += '<tr><td>' + escapeHtml(d.filename) + '</td>'
                + '<td>' + d.sample_count + '</td>'
                + '<td>' + (d.size_bytes/1024).toFixed(1) + ' KB</td>'
                + '<td>' + d.created.substring(0,16).replace('T',' ') + '</td>'
                + '<td>'
                + '<button class="btn btn-small" style="font-size:0.65rem;padding:2px 6px;margin-right:4px" '
                + 'onclick="trPreviewDataset(\'' + escapeHtml(d.filename) + '\')">Preview</button>'
                + '<button class="btn btn-danger btn-small" style="font-size:0.65rem;padding:2px 6px" '
                + 'onclick="trDeleteDataset(\'' + escapeHtml(d.filename) + '\')">Delete</button>'
                + '</td></tr>';
        });
        html += '</tbody></table>';
        container.innerHTML = html;
    });
}

function trPreviewDataset(filename) {
    postJSON('/llm-trainer/dataset/preview', {filename: filename, limit: 5}).then(function(data) {
        if (data.error) { alert(data.error); return; }
        var html = '<h4>Preview: ' + escapeHtml(filename) + '</h4>';
        (data.samples || []).forEach(function(s, i) {
            html += '<pre class="output-panel" style="font-size:0.75rem;margin-bottom:4px;max-height:150px;overflow-y:auto">'
                + escapeHtml(JSON.stringify(s, null, 2)) + '</pre>';
        });
        document.getElementById('datasets-list').innerHTML += html;
    });
}

function trDeleteDataset(filename) {
    if (!confirm('Delete ' + filename + '?')) return;
    postJSON('/llm-trainer/dataset/delete', {filename: filename}).then(function() {
        trListDatasets();
        trRefreshDatasetSelect();
    });
}

function trRefreshDatasetSelect() {
    fetchJSON('/llm-trainer/dataset/list').then(function(data) {
        var sel = document.getElementById('tr-dataset');
        sel.innerHTML = '<option value="">Select dataset...</option>';
        (data.datasets || []).forEach(function(d) {
            sel.innerHTML += '<option value="' + escapeHtml(d.path) + '">' + escapeHtml(d.filename)
                + ' (' + d.sample_count + ' samples)</option>';
        });
    });
}

/* ── Model Browser ── */
var _browserCurrentDir = '';
var _browserParentDir = '';

function trOpenBrowser() {
    document.getElementById('model-browser-overlay').style.display = 'flex';
    trBrowseDir('');  // starts at models/ directory
}

function trCloseBrowser() {
    document.getElementById('model-browser-overlay').style.display = 'none';
}

function trBrowseUp() {
    if (_browserParentDir) trBrowseDir(_browserParentDir);
}

function trBrowseDir(dir) {
    postJSON('/llm-trainer/browse', {directory: dir}).then(function(data) {
        if (data.error) {
            document.getElementById('browser-entries').innerHTML = '<p style="padding:8px;color:var(--danger)">' + escapeHtml(data.error) + '</p>';
            return;
        }
        _browserCurrentDir = data.current_dir || '';
        _browserParentDir = data.parent_dir || '';
        document.getElementById('browser-path').textContent = _browserCurrentDir;

        var entries = data.entries || [];
        if (!entries.length) {
            document.getElementById('browser-entries').innerHTML = '<p style="padding:8px;color:var(--text-muted)">Empty directory</p>';
            return;
        }
        var html = '<table class="data-table" style="font-size:0.8rem;margin:0"><tbody>';
        entries.forEach(function(e) {
            if (e.is_dir) {
                var icon = e.is_model ? '&#x1F4E6;' : '&#x1F4C1;';
                var label = e.is_model
                    ? '<span style="color:var(--success);font-weight:bold">' + escapeHtml(e.name) + '</span> <span style="font-size:0.7rem;color:var(--text-muted)">(HF model)</span>'
                    : escapeHtml(e.name);
                html += '<tr><td style="cursor:pointer" onclick="trBrowseDir(\'' + escapeHtml(e.path) + '\')">' + icon + ' ' + label + '</td>';
                if (e.is_model) {
                    html += '<td><button class="btn btn-small" style="font-size:0.65rem;padding:2px 8px" onclick="trSelectModel(\'' + escapeHtml(e.path) + '\')">Select</button></td>';
                } else {
                    html += '<td></td>';
                }
                html += '</tr>';
            } else {
                var size = e.size_gb !== undefined ? e.size_gb + ' GB' : '';
                html += '<tr><td>&#x1F4C4; ' + escapeHtml(e.name) + '</td><td style="font-size:0.7rem;color:var(--text-muted)">' + size + '</td></tr>';
            }
        });
        html += '</tbody></table>';
        document.getElementById('browser-entries').innerHTML = html;
    });
}

function trSelectModel(path) {
    document.getElementById('tr-base-model').value = path;
    trCloseBrowser();
}

/* ── Training ── */
function trStartTraining() {
    var baseModel = document.getElementById('tr-base-model').value.trim();
    var dataset = document.getElementById('tr-dataset').value;
    if (!baseModel) { alert('Click Browse to select a base model'); return; }
    if (!dataset) { alert('Please select a dataset'); return; }

    var config = {
        base_model: baseModel,
        dataset: dataset,
        lora_r: parseInt(document.getElementById('tr-lora-r').value),
        lora_alpha: parseInt(document.getElementById('tr-lora-alpha').value),
        lora_dropout: parseFloat(document.getElementById('tr-dropout').value),
        num_epochs: parseInt(document.getElementById('tr-epochs').value),
        batch_size: parseInt(document.getElementById('tr-batch').value),
        gradient_accumulation_steps: parseInt(document.getElementById('tr-grad-accum').value),
        learning_rate: parseFloat(document.getElementById('tr-lr').value),
        max_seq_length: parseInt(document.getElementById('tr-seq-len').value),
        use_4bit: document.getElementById('tr-4bit').checked,
        use_unsloth: document.getElementById('tr-unsloth').checked,
    };

    var btn = document.getElementById('btn-train-start');
    setLoading(btn, true);
    postJSON('/llm-trainer/train/start', config).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            alert('Training failed: ' + data.error);
            return;
        }
        document.getElementById('btn-train-start').style.display = 'none';
        document.getElementById('btn-train-stop').style.display = '';
        trStartPolling();
    }).catch(function() { setLoading(btn, false); });
}

function trStopTraining() {
    postJSON('/llm-trainer/train/stop', {}).then(function() {
        trStopPolling();
        document.getElementById('btn-train-start').style.display = '';
        document.getElementById('btn-train-stop').style.display = 'none';
        trUpdateStatus();
    });
}

function trStartPolling() {
    if (_trPollInterval) clearInterval(_trPollInterval);
    _trPollInterval = setInterval(trUpdateStatus, 3000);
    trUpdateStatus();
}

function trStopPolling() {
    if (_trPollInterval) { clearInterval(_trPollInterval); _trPollInterval = null; }
}

function trUpdateStatus() {
    fetchJSON('/llm-trainer/train/status').then(function(data) {
        document.getElementById('tr-phase').textContent = data.phase || 'idle';
        document.getElementById('tr-progress').textContent = (data.progress || 0) + '%';
        document.getElementById('tr-message').textContent = data.message || '';
        if (data.training_log) {
            document.getElementById('training-log').textContent = data.training_log;
            var log = document.getElementById('training-log');
            log.scrollTop = log.scrollHeight;
        }
        if (!data.training_running && _trPollInterval) {
            trStopPolling();
            document.getElementById('btn-train-start').style.display = '';
            document.getElementById('btn-train-stop').style.display = 'none';
        }
    });
}

/* ── Conversion ── */
function trListAdapters() {
    fetchJSON('/llm-trainer/adapters').then(function(data) {
        var adapters = data.adapters || [];
        var container = document.getElementById('adapters-list');
        if (!adapters.length) {
            container.innerHTML = '<p class="empty-state">No LoRA adapters found. Train a model first.</p>';
            return;
        }
        var html = '<table class="data-table" style="font-size:0.8rem"><thead><tr>'
            + '<th>Name</th><th>Base Model</th><th>LoRA r</th><th>Action</th></tr></thead><tbody>';
        adapters.forEach(function(a) {
            html += '<tr><td>' + escapeHtml(a.name) + '</td>'
                + '<td>' + escapeHtml(a.base_model || '—') + '</td>'
                + '<td>' + (a.r || '—') + '</td>'
                + '<td><button class="btn btn-small" style="font-size:0.65rem;padding:2px 6px" '
                + 'onclick="document.getElementById(\'cv-adapter\').value=\'' + escapeHtml(a.path) + '\'">Select</button></td></tr>';
        });
        html += '</tbody></table>';
        container.innerHTML = html;
    });
}

function trConvert() {
    var adapter = document.getElementById('cv-adapter').value.trim();
    var output = document.getElementById('cv-output').value.trim();
    var quant = document.getElementById('cv-quant').value;
    if (!adapter) { alert('Enter or select an adapter path'); return; }
    if (!output) { alert('Enter an output name'); return; }

    var btn = document.getElementById('btn-convert');
    setLoading(btn, true);
    renderOutput('convert-result', 'Merging and converting — this may take a while...');
    postJSON('/llm-trainer/convert', {
        adapter_path: adapter,
        output_name: output,
        quantization: quant,
    }).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            renderOutput('convert-result', 'Error: ' + data.error);
        } else if (data.partial) {
            renderOutput('convert-result', data.message);
        } else {
            renderOutput('convert-result', 'GGUF model saved!\n  Path: ' + data.output_path
                + '\n  Size: ' + (data.size_bytes / (1024*1024*1024)).toFixed(2) + ' GB');
            trListModels();
        }
    }).catch(function() { setLoading(btn, false); });
}

function trListModels() {
    fetchJSON('/llm-trainer/models').then(function(data) {
        var models = data.models || [];
        var container = document.getElementById('models-list');
        if (!models.length) {
            container.innerHTML = '<p class="empty-state">No GGUF models found.</p>';
            return;
        }
        var html = '<table class="data-table" style="font-size:0.8rem"><thead><tr>'
            + '<th>Name</th><th>Size</th><th>Modified</th></tr></thead><tbody>';
        models.forEach(function(m) {
            html += '<tr><td>' + escapeHtml(m.filename) + '</td>'
                + '<td>' + m.size_gb + ' GB</td>'
                + '<td>' + m.modified.substring(0,16).replace('T',' ') + '</td></tr>';
        });
        html += '</tbody></table>';
        container.innerHTML = html;

        // Update evaluate model select
        var sel = document.getElementById('ev-model');
        sel.innerHTML = '<option value="">Select model...</option>';
        models.forEach(function(m) {
            sel.innerHTML += '<option value="' + escapeHtml(m.path) + '">' + escapeHtml(m.filename)
                + ' (' + m.size_gb + ' GB)</option>';
        });
    });
}

/* ── Evaluate ── */
function trAddPrompt() {
    var div = document.createElement('div');
    div.className = 'input-row';
    div.style.marginBottom = '4px';
    div.innerHTML = '<input type="text" class="eval-prompt" placeholder="Enter test prompt..." style="flex:1">'
        + '<button class="btn btn-small" style="font-size:0.65rem;padding:2px 6px;margin-left:4px" '
        + 'onclick="this.parentElement.remove()">X</button>';
    document.getElementById('eval-prompts').appendChild(div);
}

function trEvaluate() {
    var model = document.getElementById('ev-model').value;
    if (!model) { alert('Select a model to evaluate'); return; }

    var prompts = [];
    document.querySelectorAll('.eval-prompt').forEach(function(el) {
        if (el.value.trim()) prompts.push(el.value.trim());
    });
    if (!prompts.length) { alert('Add at least one test prompt'); return; }

    var btn = document.getElementById('btn-evaluate');
    setLoading(btn, true);
    document.getElementById('eval-results').innerHTML = '<p style="color:var(--text-muted)">Running evaluation — loading model and generating responses...</p>';

    postJSON('/llm-trainer/evaluate', {model_path: model, prompts: prompts}).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            document.getElementById('eval-results').innerHTML = '<p style="color:var(--danger)">Error: ' + escapeHtml(data.error) + '</p>';
            return;
        }
        var html = '';
        (data.results || []).forEach(function(r, i) {
            html += '<div style="margin-bottom:12px;border:1px solid var(--border);border-radius:6px;padding:12px">'
                + '<div style="font-weight:bold;margin-bottom:6px;color:var(--accent)">Prompt: ' + escapeHtml(r.prompt) + '</div>'
                + '<pre class="output-panel scrollable" style="max-height:200px;font-size:0.78rem;margin:0">'
                + escapeHtml(r.response) + '</pre>'
                + '<div style="font-size:0.7rem;color:var(--text-muted);margin-top:4px">Response length: ' + r.length + ' chars</div>'
                + '</div>';
        });
        document.getElementById('eval-results').innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

/* ── Init ── */
document.addEventListener('DOMContentLoaded', function() {
    trRefreshDatasetSelect();
    trListModels();
});
</script>
{% endblock %}
