<!DOCTYPE html>
<html>
<head>
    <title>Ping LLMs</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        table {
            border-collapse: collapse;
            width: 100%;
            margin-top: 20px;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
            vertical-align: top;
        }
        th {
            background-color: #f2f2f2;
        }
        tr:nth-child(even) {
            background-color: #f9f9f9;
        }
        .status-success { color: green; }
        .status-error { color: red; }
        .status-pinging { color: #666; font-style: italic; }
        .status-idle { color: #888; }
        .back-link {
            margin-bottom: 20px;
            display: inline-block;
        }
        .loading { color: #666; font-style: italic; }
        @keyframes ellipsis {
            0%   { content: '.'; }
            33%  { content: '..'; }
            66%  { content: '...'; }
            100% { content: '.'; }
        }
        .pinging::after {
            content: '.';
            animation: ellipsis 1.5s infinite;
            display: inline-block;
            width: 1em;
            text-align: left;
        }
        .toolbar {
            margin-bottom: 12px;
        }
        button.ping-btn,
        button.ping-all-btn {
            cursor: pointer;
            padding: 4px 10px;
        }
        button.ping-all-btn {
            font-size: 1em;
            padding: 8px 16px;
        }
        button:disabled {
            cursor: not-allowed;
            opacity: 0.6;
        }
    </style>
</head>
<body>
    <a href="/admin" class="back-link">← Back to Admin</a>
    <h1>LLM Ping Results</h1>
    <div class="toolbar">
        <button id="pingAllBtn" class="ping-all-btn" disabled>Ping All</button>
        <span id="status" class="loading">Loading models…</span>
    </div>
    <table>
        <thead>
            <tr>
                <th>LLM Name</th>
                <th>Priority</th>
                <th>Action</th>
                <th>Status</th>
                <th>Response Time</th>
                <th>Response</th>
            </tr>
        </thead>
        <tbody id="results"></tbody>
    </table>

    <script>
        const resultsBody = document.getElementById('results');
        const pingAllBtn = document.getElementById('pingAllBtn');
        const statusEl = document.getElementById('status');

        let models = [];

        function escapeHtml(s) {
            return String(s ?? '').replace(/[&<>"']/g, c => ({
                '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
            }[c]));
        }

        function rowId(model) {
            return 'row-' + model.display_name.replace(/[^a-zA-Z0-9_-]/g, '_');
        }

        function setRowState(model, state) {
            const row = document.getElementById(rowId(model));
            if (!row) return;
            const statusCell = row.querySelector('.status-cell');
            const timeCell = row.querySelector('.time-cell');
            const respCell = row.querySelector('.response-cell');
            const btn = row.querySelector('.ping-btn');

            if (state.status === 'pinging') {
                statusCell.className = 'status-cell pinging';
                statusCell.textContent = 'pinging';
                timeCell.textContent = '';
                respCell.textContent = '';
                btn.disabled = true;
                return;
            }

            statusCell.className = 'status-cell status-' + state.status;
            statusCell.textContent = state.status;
            timeCell.textContent = (state.response_time ?? 0) + 'ms';
            respCell.textContent = state.response ?? '';
            btn.disabled = false;
        }

        function renderTable() {
            if (models.length === 0) {
                resultsBody.innerHTML = '<tr><td colspan="6" class="loading">No models configured.</td></tr>';
                return;
            }
            const rows = models.map(m => `
                <tr id="${rowId(m)}">
                    <td>${escapeHtml(m.display_name)}</td>
                    <td>${m.priority === null || m.priority === undefined ? '' : escapeHtml(m.priority)}</td>
                    <td><button class="ping-btn" data-profile="${escapeHtml(m.profile)}" data-llm="${escapeHtml(m.llm_name)}">Ping</button></td>
                    <td class="status-cell status-idle">idle</td>
                    <td class="time-cell"></td>
                    <td class="response-cell"></td>
                </tr>
            `);
            resultsBody.innerHTML = rows.join('');

            resultsBody.querySelectorAll('.ping-btn').forEach(btn => {
                btn.addEventListener('click', () => {
                    const m = {
                        profile: btn.dataset.profile,
                        llm_name: btn.dataset.llm,
                        display_name: btn.dataset.profile + ':' + btn.dataset.llm,
                    };
                    pingOne(m);
                });
            });
        }

        async function pingOne(model) {
            setRowState(model, { status: 'pinging' });
            try {
                const params = new URLSearchParams({
                    profile: model.profile,
                    llm_name: model.llm_name,
                });
                const resp = await fetch('/ping/one?' + params.toString());
                const data = await resp.json();
                setRowState(model, data);
                return data;
            } catch (exc) {
                setRowState(model, {
                    status: 'error',
                    response_time: 0,
                    response: String(exc),
                });
            }
        }

        async function pingAll() {
            pingAllBtn.disabled = true;
            statusEl.textContent = 'Pinging all models…';
            statusEl.className = 'loading';
            for (const m of models) {
                await pingOne(m);
            }
            statusEl.textContent = 'Done.';
            statusEl.className = '';
            pingAllBtn.disabled = false;
        }

        async function loadModels() {
            try {
                const resp = await fetch('/ping/list');
                if (!resp.ok) throw new Error('HTTP ' + resp.status);
                const data = await resp.json();
                models = data.models || [];
                renderTable();
                pingAllBtn.disabled = models.length === 0;
                statusEl.textContent = models.length + ' models loaded.';
                statusEl.className = '';
            } catch (exc) {
                statusEl.textContent = 'Failed to load models: ' + exc;
                statusEl.className = 'status-error';
                resultsBody.innerHTML = '';
            }
        }

        pingAllBtn.addEventListener('click', pingAll);
        loadModels();
    </script>
</body>
</html>
