<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FraiseQL APQ Monitoring Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: #333;
            padding: 20px;
            min-height: 100vh;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
        }

        header {
            background: white;
            border-radius: 12px;
            padding: 30px;
            margin-bottom: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        h1 {
            color: #667eea;
            font-size: 2.5em;
            margin-bottom: 10px;
        }

        .subtitle {
            color: #666;
            font-size: 1.1em;
        }

        .health-badge {
            display: inline-block;
            padding: 8px 16px;
            border-radius: 20px;
            font-weight: 600;
            font-size: 0.9em;
            margin-left: 15px;
            text-transform: uppercase;
        }

        .health-healthy {
            background: #10b981;
            color: white;
        }

        .health-warning {
            background: #f59e0b;
            color: white;
        }

        .health-critical {
            background: #ef4444;
            color: white;
        }

        .grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin-bottom: 20px;
        }

        .card {
            background: white;
            border-radius: 12px;
            padding: 25px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            transition: transform 0.2s, box-shadow 0.2s;
        }

        .card:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
        }

        .card-title {
            font-size: 0.9em;
            color: #666;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            margin-bottom: 10px;
            font-weight: 600;
        }

        .card-value {
            font-size: 2.5em;
            font-weight: 700;
            color: #667eea;
            margin-bottom: 5px;
        }

        .card-label {
            font-size: 0.9em;
            color: #999;
        }

        .chart-card {
            grid-column: span 2;
        }

        .full-width {
            grid-column: 1 / -1;
        }

        .progress-bar {
            width: 100%;
            height: 10px;
            background: #e5e7eb;
            border-radius: 5px;
            overflow: hidden;
            margin-top: 10px;
        }

        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
            transition: width 0.3s ease;
        }

        table {
            width: 100%;
            border-collapse: collapse;
        }

        th, td {
            text-align: left;
            padding: 12px;
            border-bottom: 1px solid #e5e7eb;
        }

        th {
            background: #f9fafb;
            font-weight: 600;
            color: #667eea;
            text-transform: uppercase;
            font-size: 0.85em;
            letter-spacing: 0.5px;
        }

        tr:hover {
            background: #f9fafb;
        }

        .warning-box {
            background: #fef3c7;
            border-left: 4px solid #f59e0b;
            padding: 15px;
            border-radius: 6px;
            margin-top: 15px;
        }

        .warning-box h4 {
            color: #f59e0b;
            margin-bottom: 8px;
        }

        .warning-box ul {
            list-style-position: inside;
            color: #92400e;
        }

        .refresh-info {
            text-align: right;
            color: white;
            font-size: 0.9em;
            margin-bottom: 10px;
            padding: 10px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 8px;
        }

        .loading {
            display: inline-block;
            width: 12px;
            height: 12px;
            border: 2px solid rgba(255, 255, 255, 0.3);
            border-top-color: white;
            border-radius: 50%;
            animation: spin 0.6s linear infinite;
            margin-left: 8px;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        .metric-trend {
            font-size: 0.85em;
            margin-top: 5px;
        }

        .trend-up {
            color: #10b981;
        }

        .trend-down {
            color: #ef4444;
        }

        .hash-truncate {
            font-family: 'Courier New', monospace;
            color: #667eea;
        }

        .footer {
            text-align: center;
            color: rgba(255, 255, 255, 0.8);
            margin-top: 30px;
            font-size: 0.9em;
        }

        @media (max-width: 768px) {
            .chart-card {
                grid-column: span 1;
            }

            h1 {
                font-size: 1.8em;
            }

            .card-value {
                font-size: 2em;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="refresh-info">
            Last updated: <span id="lastUpdate">Loading...</span>
            <span class="loading"></span>
        </div>

        <header>
            <h1>
                🚀 FraiseQL APQ Dashboard
                <span id="healthBadge" class="health-badge health-healthy">Healthy</span>
            </h1>
            <p class="subtitle">Automatic Persisted Queries - Real-time Performance Monitoring</p>
        </header>

        <!-- Key Metrics Cards -->
        <div class="grid">
            <div class="card">
                <div class="card-title">Query Cache Hit Rate</div>
                <div class="card-value" id="queryCacheHitRate">--</div>
                <div class="progress-bar">
                    <div class="progress-fill" id="queryCacheProgress"></div>
                </div>
                <div class="card-label">Target: >70%</div>
            </div>

            <div class="card">
                <div class="card-title">Response Cache Hit Rate</div>
                <div class="card-value" id="responseCacheHitRate">--</div>
                <div class="progress-bar">
                    <div class="progress-fill" id="responseCacheProgress"></div>
                </div>
                <div class="card-label">Target: >50% (if enabled)</div>
            </div>

            <div class="card">
                <div class="card-title">Total Requests</div>
                <div class="card-value" id="totalRequests">--</div>
                <div class="card-label">Since startup</div>
            </div>

            <div class="card">
                <div class="card-title">Stored Queries</div>
                <div class="card-value" id="storedQueries">--</div>
                <div class="card-label">In cache</div>
            </div>

            <div class="card">
                <div class="card-title">Cache Size</div>
                <div class="card-value" id="cacheSize">--</div>
                <div class="card-label">Memory usage</div>
            </div>

            <div class="card">
                <div class="card-title">Overall Hit Rate</div>
                <div class="card-value" id="overallHitRate">--</div>
                <div class="card-label">Combined cache efficiency</div>
            </div>
        </div>

        <!-- Charts -->
        <div class="grid">
            <div class="card chart-card">
                <h3 class="card-title">Query Cache Performance</h3>
                <canvas id="queryCacheChart"></canvas>
            </div>

            <div class="card chart-card">
                <h3 class="card-title">Response Cache Performance</h3>
                <canvas id="responseCacheChart"></canvas>
            </div>
        </div>

        <!-- Top Queries Table -->
        <div class="card full-width">
            <h3 class="card-title">🔥 Top Queries by Usage</h3>
            <table>
                <thead>
                    <tr>
                        <th>Query Hash</th>
                        <th>Total Requests</th>
                        <th>Cache Hits</th>
                        <th>Cache Misses</th>
                        <th>Hit Rate</th>
                        <th>Avg Parse Time</th>
                        <th>Last Seen</th>
                    </tr>
                </thead>
                <tbody id="topQueriesTable">
                    <tr>
                        <td colspan="7" style="text-align: center; padding: 30px; color: #999;">
                            Loading top queries...
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>

        <!-- Warnings -->
        <div id="warningsContainer"></div>

        <div class="footer">
            FraiseQL APQ Monitoring Dashboard • Auto-refreshes every 5 seconds •
            <a href="/admin/apq/stats" style="color: white;">JSON API</a>
        </div>
    </div>

    <script>
        // Configuration
        const REFRESH_INTERVAL = 5000; // 5 seconds
        const API_BASE = '/admin/apq';

        // Chart instances
        let queryCacheChart = null;
        let responseCacheChart = null;

        // Initialize dashboard
        async function initDashboard() {
            // Create charts
            createQueryCacheChart();
            createResponseCacheChart();

            // Load initial data
            await refreshData();

            // Set up auto-refresh
            setInterval(refreshData, REFRESH_INTERVAL);
        }

        // Refresh all data
        async function refreshData() {
            try {
                const [stats, topQueries] = await Promise.all([
                    fetch(`${API_BASE}/stats`).then(r => r.json()),
                    fetch(`${API_BASE}/top-queries?limit=10`).then(r => r.json())
                ]);

                updateMetrics(stats);
                updateCharts(stats);
                updateTopQueries(topQueries);
                updateWarnings(stats);
                updateLastRefresh();

            } catch (error) {
                console.error('Failed to refresh data:', error);
            }
        }

        // Update metric cards
        function updateMetrics(stats) {
            const current = stats.current;
            const queryCache = current.query_cache;
            const responseCache = current.response_cache;
            const storage = current.storage;
            const performance = current.performance;

            // Query cache hit rate
            const queryCacheRate = (queryCache.hit_rate * 100).toFixed(1);
            document.getElementById('queryCacheHitRate').textContent = `${queryCacheRate}%`;
            document.getElementById('queryCacheProgress').style.width = `${queryCacheRate}%`;

            // Response cache hit rate
            const responseCacheRate = (responseCache.hit_rate * 100).toFixed(1);
            document.getElementById('responseCacheHitRate').textContent = `${responseCacheRate}%`;
            document.getElementById('responseCacheProgress').style.width = `${responseCacheRate}%`;

            // Total requests
            document.getElementById('totalRequests').textContent = performance.total_requests.toLocaleString();

            // Stored queries
            document.getElementById('storedQueries').textContent = storage.stored_queries.toLocaleString();

            // Cache size
            const sizeKB = (storage.total_bytes / 1024).toFixed(1);
            document.getElementById('cacheSize').textContent = `${sizeKB} KB`;

            // Overall hit rate
            const overallRate = (performance.overall_hit_rate * 100).toFixed(1);
            document.getElementById('overallHitRate').textContent = `${overallRate}%`;

            // Update health badge
            updateHealthBadge(stats.health);
        }

        // Update health badge
        function updateHealthBadge(health) {
            const badge = document.getElementById('healthBadge');
            badge.textContent = health.status.charAt(0).toUpperCase() + health.status.slice(1);
            badge.className = 'health-badge health-' + health.status;
        }

        // Create query cache chart
        function createQueryCacheChart() {
            const ctx = document.getElementById('queryCacheChart').getContext('2d');
            queryCacheChart = new Chart(ctx, {
                type: 'doughnut',
                data: {
                    labels: ['Cache Hits', 'Cache Misses'],
                    datasets: [{
                        data: [0, 0],
                        backgroundColor: ['#10b981', '#ef4444'],
                        borderWidth: 0
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: true,
                    plugins: {
                        legend: {
                            position: 'bottom'
                        },
                        title: {
                            display: true,
                            text: 'Query String Cache'
                        }
                    }
                }
            });
        }

        // Create response cache chart
        function createResponseCacheChart() {
            const ctx = document.getElementById('responseCacheChart').getContext('2d');
            responseCacheChart = new Chart(ctx, {
                type: 'doughnut',
                data: {
                    labels: ['Cache Hits', 'Cache Misses', 'Not Enabled'],
                    datasets: [{
                        data: [0, 0, 1],
                        backgroundColor: ['#10b981', '#ef4444', '#d1d5db'],
                        borderWidth: 0
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: true,
                    plugins: {
                        legend: {
                            position: 'bottom'
                        },
                        title: {
                            display: true,
                            text: 'Response Cache'
                        }
                    }
                }
            });
        }

        // Update charts
        function updateCharts(stats) {
            const queryCache = stats.current.query_cache;
            const responseCache = stats.current.response_cache;

            // Update query cache chart
            queryCacheChart.data.datasets[0].data = [
                queryCache.hits,
                queryCache.misses
            ];
            queryCacheChart.update();

            // Update response cache chart
            const responseCacheEnabled = responseCache.hits + responseCache.misses > 0;
            if (responseCacheEnabled) {
                responseCacheChart.data.datasets[0].data = [
                    responseCache.hits,
                    responseCache.misses,
                    0
                ];
            } else {
                responseCacheChart.data.datasets[0].data = [0, 0, 1];
            }
            responseCacheChart.update();
        }

        // Update top queries table
        function updateTopQueries(data) {
            const tbody = document.getElementById('topQueriesTable');

            if (!data.top_queries || data.top_queries.length === 0) {
                tbody.innerHTML = `
                    <tr>
                        <td colspan="7" style="text-align: center; padding: 30px; color: #999;">
                            No queries tracked yet. Make some APQ requests to see data here.
                        </td>
                    </tr>
                `;
                return;
            }

            tbody.innerHTML = data.top_queries.map(query => {
                const hitRate = ((query.hit_count / query.total_requests) * 100).toFixed(1);
                const parseTime = query.avg_parse_time_ms > 0
                    ? `${query.avg_parse_time_ms.toFixed(1)}ms`
                    : 'N/A';
                const lastSeen = new Date(query.last_seen).toLocaleTimeString();

                return `
                    <tr>
                        <td><span class="hash-truncate">${query.hash}</span></td>
                        <td><strong>${query.total_requests}</strong></td>
                        <td style="color: #10b981;">${query.hit_count}</td>
                        <td style="color: #ef4444;">${query.miss_count}</td>
                        <td><strong>${hitRate}%</strong></td>
                        <td>${parseTime}</td>
                        <td>${lastSeen}</td>
                    </tr>
                `;
            }).join('');
        }

        // Update warnings
        function updateWarnings(stats) {
            const container = document.getElementById('warningsContainer');
            const warnings = stats.health.warnings;

            if (warnings.length === 0) {
                container.innerHTML = '';
                return;
            }

            container.innerHTML = `
                <div class="card full-width">
                    <div class="warning-box">
                        <h4>⚠️ Performance Warnings</h4>
                        <ul>
                            ${warnings.map(w => `<li>${w}</li>`).join('')}
                        </ul>
                    </div>
                </div>
            `;
        }

        // Update last refresh time
        function updateLastRefresh() {
            const now = new Date();
            document.getElementById('lastUpdate').textContent = now.toLocaleTimeString();
        }

        // Initialize when page loads
        document.addEventListener('DOMContentLoaded', initDashboard);
    </script>
</body>
</html>
