{% extends "_base.html" %}

{% block title %}效能監控 - MES Dashboard{% endblock %}

{% block head_extra %}
    <script src="{{ url_for('static', filename='js/chart.umd.min.js') }}"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft JhengHei', Arial, sans-serif;
            background: #f5f7fa;
            color: #222;
        }

        .shell {
            max-width: 1400px;
            margin: 0 auto;
            padding: 20px;
        }

        .header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 24px;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
            margin-bottom: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .header-left h1 {
            font-size: 24px;
            margin-bottom: 4px;
        }

        .header-left p {
            font-size: 14px;
            opacity: 0.9;
        }

        .header-right {
            display: flex;
            align-items: center;
            gap: 16px;
        }

        .back-link-header {
            background: rgba(255, 255, 255, 0.2);
            color: white;
            border: 1px solid rgba(255, 255, 255, 0.3);
            padding: 8px 16px;
            border-radius: 6px;
            text-decoration: none;
            font-size: 14px;
            transition: background 0.2s ease;
        }

        .back-link-header:hover {
            background: rgba(255, 255, 255, 0.3);
            text-decoration: none;
        }

        .refresh-controls {
            display: flex;
            align-items: center;
            gap: 12px;
        }

        .refresh-btn, .auto-refresh-toggle {
            background: rgba(255, 255, 255, 0.2);
            color: white;
            border: 1px solid rgba(255, 255, 255, 0.3);
            padding: 8px 16px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            transition: background 0.2s ease;
        }

        .refresh-btn:hover, .auto-refresh-toggle:hover {
            background: rgba(255, 255, 255, 0.3);
        }

        .auto-refresh-toggle.active {
            background: rgba(255, 255, 255, 0.4);
        }

        .grid {
            display: grid;
            gap: 20px;
            margin-bottom: 20px;
        }

        .grid-4 {
            grid-template-columns: repeat(4, 1fr);
        }

        .grid-2 {
            grid-template-columns: repeat(2, 1fr);
        }

        @media (max-width: 1200px) {
            .grid-4 { grid-template-columns: repeat(2, 1fr); }
        }

        @media (max-width: 768px) {
            .grid-4, .grid-2 { grid-template-columns: 1fr; }
        }

        .card {
            background: white;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.08);
            padding: 20px;
        }

        .card-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 16px;
        }

        .card-title {
            font-size: 14px;
            color: #666;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .card-value {
            font-size: 28px;
            font-weight: 700;
            color: #333;
        }

        .card-subtitle {
            font-size: 13px;
            color: #888;
            margin-top: 4px;
        }

        .status-indicator {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            display: inline-block;
        }

        .status-healthy { background: #4caf50; }
        .status-degraded { background: #ff9800; }
        .status-error { background: #f44336; }
        .status-disabled { background: #9e9e9e; }

        .metric-row {
            display: flex;
            justify-content: space-between;
            padding: 8px 0;
            border-bottom: 1px solid #f0f0f0;
        }

        .metric-row:last-child {
            border-bottom: none;
        }

        .metric-label {
            color: #666;
            font-size: 14px;
        }

        .metric-value {
            font-weight: 600;
            font-size: 14px;
        }

        .chart-container {
            height: 200px;
            margin-top: 16px;
        }

        .panel {
            background: white;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.08);
            overflow: hidden;
        }

        .panel-header {
            padding: 16px 20px;
            border-bottom: 1px solid #eee;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .panel-header h2 {
            font-size: 18px;
            font-weight: 600;
        }

        .panel-body {
            padding: 20px;
        }

        .log-filters {
            display: flex;
            gap: 12px;
            margin-bottom: 16px;
            flex-wrap: wrap;
        }

        .log-filters select, .log-filters input {
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 14px;
        }

        .log-filters input {
            flex: 1;
            min-width: 200px;
        }

        .log-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 13px;
        }

        .log-table th, .log-table td {
            padding: 10px 12px;
            text-align: left;
            border-bottom: 1px solid #eee;
        }

        .log-table th {
            background: #f8f9fa;
            font-weight: 600;
            color: #555;
        }

        .log-level {
            display: inline-block;
            padding: 2px 8px;
            border-radius: 4px;
            font-size: 11px;
            font-weight: 600;
        }

        .log-level-INFO { background: #e3f2fd; color: #1976d2; }
        .log-level-WARNING { background: #fff3e0; color: #e65100; }
        .log-level-ERROR { background: #ffebee; color: #c62828; }
        .log-level-DEBUG { background: #f5f5f5; color: #616161; }

        .log-message {
            max-width: 500px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .back-link {
            display: inline-block;
            margin-top: 16px;
            color: #667eea;
            text-decoration: none;
            font-size: 14px;
        }

        .pagination {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 8px;
            margin-top: 16px;
            padding-top: 16px;
            border-top: 1px solid #eee;
        }

        .pagination button {
            padding: 6px 12px;
            border: 1px solid #ddd;
            background: white;
            border-radius: 4px;
            cursor: pointer;
            font-size: 13px;
            transition: background 0.2s ease;
        }

        .pagination button:hover:not(:disabled) {
            background: #f0f0f0;
        }

        .pagination button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        .pagination .page-info {
            font-size: 13px;
            color: #666;
            padding: 0 12px;
        }

        .last-update {
            font-size: 12px;
            color: rgba(255,255,255,0.8);
        }
    </style>
{% endblock %}

{% block content %}
    <div class="shell">
        <div class="header">
            <div class="header-left">
                <h1>效能監控儀表板</h1>
                <p>系統狀態、查詢效能與日誌記錄</p>
            </div>
            <div class="header-right">
                <div class="last-update">
                    <span id="lastUpdate">--</span>
                </div>
                <div class="refresh-controls">
                    <button class="auto-refresh-toggle active" id="autoRefreshBtn" onclick="toggleAutoRefresh()">
                        自動更新: 開
                    </button>
                    <button class="refresh-btn" onclick="refreshAll()">
                        立即重新整理
                    </button>
                </div>
                <a href="{{ url_for('portal_index') }}" class="back-link-header">← 返回首頁</a>
            </div>
        </div>

        <!-- System Status Cards -->
        <div class="grid grid-4">
            <div class="card">
                <div class="card-header">
                    <span class="card-title">Database</span>
                    <span class="status-indicator" id="dbStatus"></span>
                </div>
                <div class="card-value" id="dbLatency">--</div>
                <div class="card-subtitle">連線延遲</div>
            </div>

            <div class="card">
                <div class="card-header">
                    <span class="card-title">Redis</span>
                    <span class="status-indicator" id="redisStatus"></span>
                </div>
                <div class="card-value" id="redisInfo">--</div>
                <div class="card-subtitle">快取狀態</div>
            </div>

            <div class="card">
                <div class="card-header">
                    <span class="card-title">Circuit Breaker</span>
                    <span class="status-indicator" id="cbStatus"></span>
                </div>
                <div class="card-value" id="cbState">--</div>
                <div class="card-subtitle" id="cbDetail">--</div>
            </div>

            <div class="card">
                <div class="card-header">
                    <span class="card-title">Worker</span>
                    <span class="status-indicator status-healthy"></span>
                </div>
                <div class="card-value" id="workerPid">--</div>
                <div class="card-subtitle">Process ID</div>
            </div>
        </div>

        <!-- Query Performance -->
        <div class="grid grid-2">
            <div class="card">
                <div class="card-header">
                    <span class="card-title">查詢效能</span>
                </div>
                <div class="metric-row">
                    <span class="metric-label">P50 延遲</span>
                    <span class="metric-value" id="p50">-- ms</span>
                </div>
                <div class="metric-row">
                    <span class="metric-label">P95 延遲</span>
                    <span class="metric-value" id="p95">-- ms</span>
                </div>
                <div class="metric-row">
                    <span class="metric-label">P99 延遲</span>
                    <span class="metric-value" id="p99">-- ms</span>
                </div>
                <div class="metric-row">
                    <span class="metric-label">總查詢數</span>
                    <span class="metric-value" id="queryCount">--</span>
                </div>
                <div class="metric-row">
                    <span class="metric-label">慢查詢數 (>1s)</span>
                    <span class="metric-value" id="slowCount">--</span>
                </div>
                <div class="metric-row">
                    <span class="metric-label">慢查詢率</span>
                    <span class="metric-value" id="slowRate">--%</span>
                </div>
            </div>

            <div class="card">
                <div class="card-header">
                    <span class="card-title">延遲分布 (最近 100 筆)</span>
                </div>
                <div class="chart-container">
                    <canvas id="latencyChart"></canvas>
                </div>
            </div>
        </div>

        <!-- Worker Control Panel -->
        <div class="panel" style="margin-bottom: 20px;">
            <div class="panel-header">
                <h2>Worker 控制</h2>
            </div>
            <div class="panel-body">
                <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
                    <div>
                        <div class="metric-row">
                            <span class="metric-label">Worker PID</span>
                            <span class="metric-value" id="workerStatusPid">--</span>
                        </div>
                        <div class="metric-row">
                            <span class="metric-label">啟動時間</span>
                            <span class="metric-value" id="workerStartTime">--</span>
                        </div>
                        <div class="metric-row">
                            <span class="metric-label">冷卻狀態</span>
                            <span class="metric-value" id="workerCooldown">--</span>
                        </div>
                    </div>
                    <div>
                        <div class="metric-row">
                            <span class="metric-label">上次重啟</span>
                            <span class="metric-value" id="lastRestartTime">--</span>
                        </div>
                        <div class="metric-row">
                            <span class="metric-label">重啟者</span>
                            <span class="metric-value" id="lastRestartBy">--</span>
                        </div>
                        <div class="metric-row">
                            <span class="metric-label">重啟狀態</span>
                            <span class="metric-value" id="lastRestartStatus">--</span>
                        </div>
                    </div>
                </div>
                <div style="margin-top: 20px; text-align: center;">
                    <button
                        id="restartBtn"
                        onclick="confirmRestartWorker()"
                        style="
                            background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
                            color: white;
                            border: none;
                            padding: 12px 24px;
                            border-radius: 6px;
                            font-size: 14px;
                            font-weight: 600;
                            cursor: pointer;
                            transition: transform 0.2s ease, box-shadow 0.2s ease;
                        "
                        onmouseover="this.style.transform='scale(1.02)'; this.style.boxShadow='0 4px 12px rgba(238,90,36,0.4)';"
                        onmouseout="this.style.transform='scale(1)'; this.style.boxShadow='none';"
                    >
                        重新啟動 Workers
                    </button>
                    <p style="margin-top: 8px; font-size: 12px; color: #888;">
                        這將優雅地重新載入所有 Worker 程序 (不會中斷現有請求)
                    </p>
                </div>
            </div>
        </div>

        <!-- Restart Confirmation Modal -->
        <div id="restartModal" style="
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,0.5);
            z-index: 1000;
            justify-content: center;
            align-items: center;
        ">
            <div style="
                background: white;
                border-radius: 10px;
                padding: 24px;
                max-width: 400px;
                width: 90%;
                box-shadow: 0 10px 40px rgba(0,0,0,0.2);
            ">
                <h3 style="margin-bottom: 16px; color: #333;">確認重新啟動 Workers?</h3>
                <p style="color: #666; margin-bottom: 20px; font-size: 14px;">
                    這將發送信號給 Gunicorn master 程序，優雅地重新載入所有 worker。
                    現有請求會完成處理後才關閉。
                </p>
                <div style="display: flex; justify-content: flex-end; gap: 12px;">
                    <button
                        onclick="hideRestartModal()"
                        style="
                            padding: 8px 16px;
                            border: 1px solid #ddd;
                            background: white;
                            border-radius: 6px;
                            cursor: pointer;
                        "
                    >取消</button>
                    <button
                        onclick="executeRestart()"
                        style="
                            padding: 8px 16px;
                            border: none;
                            background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
                            color: white;
                            border-radius: 6px;
                            cursor: pointer;
                            font-weight: 600;
                        "
                    >確認重啟</button>
                </div>
            </div>
        </div>

        <!-- Log Cleanup Confirmation Modal -->
        <div id="cleanupModal" style="
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,0.5);
            z-index: 1000;
            justify-content: center;
            align-items: center;
        ">
            <div style="
                background: white;
                border-radius: 10px;
                padding: 24px;
                max-width: 400px;
                width: 90%;
                box-shadow: 0 10px 40px rgba(0,0,0,0.2);
            ">
                <h3 style="margin-bottom: 16px; color: #333;">確認清理日誌?</h3>
                <p style="color: #666; margin-bottom: 20px; font-size: 14px;">
                    這將刪除超過保留期限的舊日誌，以及超過上限筆數的記錄。此操作無法復原。
                </p>
                <div style="display: flex; justify-content: flex-end; gap: 12px;">
                    <button
                        onclick="hideCleanupModal()"
                        style="
                            padding: 8px 16px;
                            border: 1px solid #ddd;
                            background: white;
                            border-radius: 6px;
                            cursor: pointer;
                        "
                    >取消</button>
                    <button
                        onclick="executeCleanup()"
                        style="
                            padding: 8px 16px;
                            border: none;
                            background: #ff9800;
                            color: white;
                            border-radius: 6px;
                            cursor: pointer;
                            font-weight: 600;
                        "
                    >確認清理</button>
                </div>
            </div>
        </div>

        <!-- Logs Panel -->
        <div class="panel">
            <div class="panel-header">
                <h2>系統日誌</h2>
                <div style="display: flex; align-items: center; gap: 16px;">
                    <span id="logStats">--</span>
                    <button
                        id="cleanupLogsBtn"
                        onclick="confirmCleanupLogs()"
                        style="
                            background: #ff9800;
                            color: white;
                            border: none;
                            padding: 6px 12px;
                            border-radius: 4px;
                            font-size: 12px;
                            cursor: pointer;
                            transition: background 0.2s ease;
                        "
                        onmouseover="this.style.background='#f57c00';"
                        onmouseout="this.style.background='#ff9800';"
                    >清理日誌</button>
                </div>
            </div>
            <div class="panel-body">
                <!-- Log Storage Info -->
                <div style="
                    background: #f8f9fa;
                    border-radius: 6px;
                    padding: 12px 16px;
                    margin-bottom: 16px;
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    flex-wrap: wrap;
                    gap: 12px;
                ">
                    <div style="display: flex; gap: 24px; flex-wrap: wrap;">
                        <div>
                            <span style="color: #666; font-size: 12px;">總筆數</span>
                            <div style="font-weight: 600;" id="logTotalCount">--</div>
                        </div>
                        <div>
                            <span style="color: #666; font-size: 12px;">檔案大小</span>
                            <div style="font-weight: 600;" id="logFileSize">--</div>
                        </div>
                        <div>
                            <span style="color: #666; font-size: 12px;">最舊記錄</span>
                            <div style="font-weight: 600;" id="logOldest">--</div>
                        </div>
                        <div>
                            <span style="color: #666; font-size: 12px;">保留天數</span>
                            <div style="font-weight: 600;" id="logRetention">--</div>
                        </div>
                        <div>
                            <span style="color: #666; font-size: 12px;">上限筆數</span>
                            <div style="font-weight: 600;" id="logMaxRows">--</div>
                        </div>
                    </div>
                </div>

                <div class="log-filters">
                    <select id="logLevel" onchange="loadLogs(true)">
                        <option value="">所有等級</option>
                        <option value="ERROR">ERROR</option>
                        <option value="WARNING">WARNING</option>
                        <option value="INFO">INFO</option>
                    </select>
                    <input type="text" id="logSearch" placeholder="搜尋關鍵字..." onkeyup="debounceLoadLogs()">
                </div>
                <div style="overflow-x: auto;">
                    <table class="log-table">
                        <thead>
                            <tr>
                                <th style="width: 160px;">時間</th>
                                <th style="width: 80px;">等級</th>
                                <th style="width: 180px;">來源</th>
                                <th>訊息</th>
                            </tr>
                        </thead>
                        <tbody id="logTableBody">
                            <tr><td colspan="4" style="text-align: center; color: #888;">載入中...</td></tr>
                        </tbody>
                    </table>
                </div>
                <!-- Pagination -->
                <div class="pagination">
                    <button id="prevPageBtn" onclick="prevPage()" disabled>← 上一頁</button>
                    <span class="page-info">
                        第 <span id="currentPage">1</span> 頁，共 <span id="totalPages">1</span> 頁
                        (<span id="displayedCount">0</span> / <span id="totalLogCount">0</span> 筆)
                    </span>
                    <button id="nextPageBtn" onclick="nextPage()" disabled>下一頁 →</button>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

{% block scripts %}
    <script>
        // ============================================================
        // State
        // ============================================================
        let autoRefresh = true;
        let refreshTimer = null;
        let latencyChart = null;
        let logSearchTimeout = null;
        const REFRESH_INTERVAL = 30000; // 30 seconds
        const PAGE_SIZE = 50;
        let currentPage = 1;
        let totalLogs = 0;
        let authErrorShown = false;

        // ============================================================
        // Auth Helper
        // ============================================================
        async function fetchWithAuth(url, options = {}) {
            const method = (options.method || 'GET').toUpperCase();
            const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
            const headers = { ...(options.headers || {}) };
            if (csrfToken && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
                headers['X-CSRF-Token'] = csrfToken;
            }
            const resp = await fetch(url, { ...options, headers, cache: 'no-store' });
            if (resp.status === 401) {
                const json = await resp.json().catch(() => ({}));
                if (!authErrorShown) {
                    authErrorShown = true;
                    alert('登入已過期，請重新登入');
                    window.location.href = '/auth/login?next=' + encodeURIComponent(window.location.pathname);
                }
                throw new Error('需要重新登入');
            }
            return resp;
        }

        // ============================================================
        // Chart Setup
        // ============================================================
        function initChart() {
            const ctx = document.getElementById('latencyChart').getContext('2d');
            latencyChart = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: [],
                    datasets: [{
                        label: 'Latency (ms)',
                        data: [],
                        backgroundColor: 'rgba(102, 126, 234, 0.6)',
                        borderColor: 'rgba(102, 126, 234, 1)',
                        borderWidth: 1
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: { display: false }
                    },
                    scales: {
                        y: {
                            beginAtZero: true,
                            title: { display: true, text: 'ms' }
                        },
                        x: {
                            display: false
                        }
                    }
                }
            });
        }

        function updateChart(latencies) {
            if (!latencyChart || !latencies || latencies.length === 0) return;

            // Convert to milliseconds
            const data = latencies.map(l => Math.round(l * 1000));
            const labels = data.map((_, i) => i + 1);

            latencyChart.data.labels = labels;
            latencyChart.data.datasets[0].data = data;
            latencyChart.update();
        }

        // ============================================================
        // Data Loading
        // ============================================================
        async function loadSystemStatus() {
            try {
                const resp = await fetchWithAuth('/admin/api/system-status');
                const json = await resp.json();
                if (!json.success) throw new Error(json.error);

                const data = json.data;

                // Database
                const dbEl = document.getElementById('dbStatus');
                dbEl.className = 'status-indicator status-' + (data.database.status === 'ok' ? 'healthy' : 'error');
                document.getElementById('dbLatency').textContent = data.database.status === 'ok' ? 'OK' : 'Error';

                // Redis
                const redisEl = document.getElementById('redisStatus');
                if (data.redis.status === 'ok') {
                    redisEl.className = 'status-indicator status-healthy';
                    document.getElementById('redisInfo').textContent = 'OK';
                } else if (data.redis.status === 'disabled') {
                    redisEl.className = 'status-indicator status-disabled';
                    document.getElementById('redisInfo').textContent = '停用';
                } else {
                    redisEl.className = 'status-indicator status-error';
                    document.getElementById('redisInfo').textContent = 'Error';
                }

                // Circuit Breaker
                const cb = data.circuit_breaker;
                const cbEl = document.getElementById('cbStatus');
                if (cb.state === 'CLOSED') {
                    cbEl.className = 'status-indicator status-healthy';
                } else if (cb.state === 'HALF_OPEN') {
                    cbEl.className = 'status-indicator status-degraded';
                } else {
                    cbEl.className = 'status-indicator status-error';
                }
                document.getElementById('cbState').textContent = cb.state;
                document.getElementById('cbDetail').textContent = cb.enabled
                    ? `失敗: ${cb.failure_count}/${cb.window_size}`
                    : '未啟用';

                // Worker
                document.getElementById('workerPid').textContent = data.worker_pid;

            } catch (e) {
                console.error('Error loading system status:', e);
            }
        }

        async function loadMetrics() {
            try {
                const resp = await fetchWithAuth('/admin/api/metrics');
                const json = await resp.json();
                if (!json.success) throw new Error(json.error);

                const data = json.data;

                document.getElementById('p50').textContent = `${data.p50_ms || 0} ms`;
                document.getElementById('p95').textContent = `${data.p95_ms || 0} ms`;
                document.getElementById('p99').textContent = `${data.p99_ms || 0} ms`;
                document.getElementById('queryCount').textContent = data.count || 0;
                document.getElementById('slowCount').textContent = data.slow_count || 0;
                document.getElementById('slowRate').textContent = `${((data.slow_rate || 0) * 100).toFixed(1)}%`;

                // Update chart
                if (data.latencies) {
                    updateChart(data.latencies);
                }

            } catch (e) {
                console.error('Error loading metrics:', e);
            }
        }

        async function loadLogs(resetPage = false) {
            try {
                if (resetPage) {
                    currentPage = 1;
                }

                const level = document.getElementById('logLevel').value;
                const q = document.getElementById('logSearch').value;
                const offset = (currentPage - 1) * PAGE_SIZE;

                let url = `/admin/api/logs?limit=${PAGE_SIZE}&offset=${offset}`;
                if (level) url += `&level=${encodeURIComponent(level)}`;
                if (q) url += `&q=${encodeURIComponent(q)}`;

                const resp = await fetchWithAuth(url);
                const json = await resp.json();
                if (!json.success) throw new Error(json.error);

                const data = json.data;
                const tbody = document.getElementById('logTableBody');

                // Update stats
                if (data.enabled && data.stats) {
                    const stats = data.stats;
                    // Use data.total for filtered count (respects level/search filters)
                    totalLogs = data.total !== undefined ? data.total : (stats.count || 0);
                    document.getElementById('logStats').textContent =
                        `共 ${stats.count} 筆 (${formatBytes(stats.size_bytes)})`;
                    document.getElementById('logTotalCount').textContent = stats.count.toLocaleString();
                    document.getElementById('logFileSize').textContent = formatBytes(stats.size_bytes);
                    document.getElementById('logOldest').textContent =
                        stats.oldest ? formatTimestamp(stats.oldest) : '--';
                    document.getElementById('logRetention').textContent =
                        stats.retention_days ? `${stats.retention_days} 天` : '--';
                    document.getElementById('logMaxRows').textContent =
                        stats.max_rows ? stats.max_rows.toLocaleString() : '--';
                } else if (!data.enabled) {
                    document.getElementById('logStats').textContent = 'Log Store 未啟用';
                    document.getElementById('logTotalCount').textContent = '未啟用';
                    document.getElementById('logFileSize').textContent = '--';
                    document.getElementById('logOldest').textContent = '--';
                    document.getElementById('logRetention').textContent = '--';
                    document.getElementById('logMaxRows').textContent = '--';
                    totalLogs = 0;
                }

                // Update pagination info
                const totalPages = Math.max(1, Math.ceil(totalLogs / PAGE_SIZE));
                const startIdx = totalLogs > 0 ? offset + 1 : 0;
                const endIdx = data.logs ? Math.min(offset + data.logs.length, totalLogs) : 0;
                document.getElementById('currentPage').textContent = currentPage;
                document.getElementById('totalPages').textContent = totalPages;
                document.getElementById('totalLogCount').textContent = totalLogs;
                document.getElementById('displayedCount').textContent = `${startIdx}-${endIdx}`;

                // Update pagination buttons
                document.getElementById('prevPageBtn').disabled = currentPage <= 1;
                document.getElementById('nextPageBtn').disabled = currentPage >= totalPages;

                // Render logs
                if (!data.logs || data.logs.length === 0) {
                    tbody.innerHTML = '<tr><td colspan="4" style="text-align: center; color: #888;">無日誌記錄</td></tr>';
                    return;
                }

                tbody.innerHTML = data.logs.map(log => `
                    <tr>
                        <td>${formatTimestamp(log.timestamp)}</td>
                        <td><span class="log-level log-level-${log.level}">${log.level}</span></td>
                        <td>${escapeHtml(log.logger_name)}</td>
                        <td class="log-message" title="${escapeHtml(log.message)}">${escapeHtml(log.message)}</td>
                    </tr>
                `).join('');

            } catch (e) {
                console.error('Error loading logs:', e);
                document.getElementById('logTableBody').innerHTML =
                    '<tr><td colspan="4" style="text-align: center; color: #c62828;">載入失敗</td></tr>';
            }
        }

        function prevPage() {
            if (currentPage > 1) {
                currentPage--;
                loadLogs();
            }
        }

        function nextPage() {
            const totalPages = Math.ceil(totalLogs / PAGE_SIZE);
            if (currentPage < totalPages) {
                currentPage++;
                loadLogs();
            }
        }

        function debounceLoadLogs() {
            if (logSearchTimeout) clearTimeout(logSearchTimeout);
            logSearchTimeout = setTimeout(() => loadLogs(true), 300);
        }

        // ============================================================
        // Worker Control
        // ============================================================
        async function loadWorkerStatus() {
            try {
                const resp = await fetchWithAuth('/admin/api/worker/status');
                const json = await resp.json();
                if (!json.success) throw new Error(json.error);

                const data = json.data;

                // Update worker info
                document.getElementById('workerStatusPid').textContent = data.worker_pid || '--';
                document.getElementById('workerStartTime').textContent =
                    data.worker_start_time ? formatTimestamp(data.worker_start_time) : '--';

                // Update recovery policy status
                const policyState = data?.resilience?.policy_state || {};
                const cooldown = data.cooldown;
                if (policyState.blocked) {
                    document.getElementById('workerCooldown').textContent = 'Guarded mode（需手動 override）';
                    document.getElementById('restartBtn').disabled = false;
                    document.getElementById('restartBtn').style.opacity = '1';
                    document.getElementById('restartBtn').style.cursor = 'pointer';
                } else if (cooldown && cooldown.active) {
                    document.getElementById('workerCooldown').textContent =
                        `冷卻中 (${cooldown.remaining_seconds}秒)`;
                    document.getElementById('restartBtn').disabled = true;
                    document.getElementById('restartBtn').style.opacity = '0.5';
                    document.getElementById('restartBtn').style.cursor = 'not-allowed';
                } else {
                    document.getElementById('workerCooldown').textContent = '可用';
                    document.getElementById('restartBtn').disabled = false;
                    document.getElementById('restartBtn').style.opacity = '1';
                    document.getElementById('restartBtn').style.cursor = 'pointer';
                }

                // Update last restart info
                const lastRestart = data.last_restart;
                if (lastRestart && lastRestart.completed_at) {
                    document.getElementById('lastRestartTime').textContent =
                        formatTimestamp(lastRestart.completed_at);
                    document.getElementById('lastRestartBy').textContent =
                        lastRestart.requested_by || '--';
                    document.getElementById('lastRestartStatus').textContent =
                        lastRestart.success ? '成功' : '失敗';
                    document.getElementById('lastRestartStatus').style.color =
                        lastRestart.success ? '#4caf50' : '#f44336';
                } else {
                    document.getElementById('lastRestartTime').textContent = '--';
                    document.getElementById('lastRestartBy').textContent = '--';
                    document.getElementById('lastRestartStatus').textContent = '--';
                }

            } catch (e) {
                console.error('Error loading worker status:', e);
            }
        }

        function confirmRestartWorker() {
            const modal = document.getElementById('restartModal');
            modal.style.display = 'flex';
        }

        function hideRestartModal() {
            document.getElementById('restartModal').style.display = 'none';
        }

        async function executeRestart() {
            hideRestartModal();

            const btn = document.getElementById('restartBtn');
            btn.disabled = true;
            btn.textContent = '重啟中...';
            btn.style.opacity = '0.5';

            try {
                let resp = await fetchWithAuth('/admin/api/worker/restart', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({})
                });
                let json = await resp.json();

                if (!json.success && resp.status === 409) {
                    const reason = window.prompt(
                        '目前 restart policy 為 guarded mode。\n請輸入 override 原因（會記錄於稽核日誌）：'
                    );
                    if (!reason || !reason.trim()) {
                        alert('已取消 override。');
                        return;
                    }

                    const acknowledged = window.confirm(
                        '確認執行 manual override？此操作將繞過 guarded mode 保護。'
                    );
                    if (!acknowledged) {
                        alert('已取消 override。');
                        return;
                    }

                    resp = await fetchWithAuth('/admin/api/worker/restart', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({
                            manual_override: true,
                            override_acknowledged: true,
                            override_reason: reason.trim()
                        })
                    });
                    json = await resp.json();
                }

                if (!json.success) {
                    alert('重啟失敗: ' + (json.error?.message || '未知錯誤'));
                    return;
                }

                // Show success message
                alert('重啟請求已送出。Workers 將在幾秒內重新載入。');

                // Poll for status update
                setTimeout(() => {
                    loadWorkerStatus();
                }, 2000);

            } catch (e) {
                console.error('Error requesting restart:', e);
                alert('重啟請求失敗: ' + e.message);
            } finally {
                btn.textContent = '重新啟動 Workers';
                loadWorkerStatus();
            }
        }

        // Close modal on outside click
        document.addEventListener('click', (e) => {
            const modal = document.getElementById('restartModal');
            if (e.target === modal) {
                hideRestartModal();
            }
            const cleanupModal = document.getElementById('cleanupModal');
            if (e.target === cleanupModal) {
                hideCleanupModal();
            }
        });

        // ============================================================
        // Log Cleanup
        // ============================================================
        function confirmCleanupLogs() {
            const modal = document.getElementById('cleanupModal');
            modal.style.display = 'flex';
        }

        function hideCleanupModal() {
            document.getElementById('cleanupModal').style.display = 'none';
        }

        async function executeCleanup() {
            hideCleanupModal();

            const btn = document.getElementById('cleanupLogsBtn');
            const originalText = btn.textContent;
            btn.disabled = true;
            btn.textContent = '清理中...';
            btn.style.opacity = '0.5';

            try {
                const resp = await fetchWithAuth('/admin/api/logs/cleanup', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' }
                });
                const json = await resp.json();

                if (!json.success) {
                    alert('清理失敗: ' + (json.error || '未知錯誤'));
                    return;
                }

                const data = json.data;
                alert(`日誌清理完成!\n\n` +
                    `已刪除: ${data.deleted} 筆\n` +
                    `清理前: ${data.before.count} 筆 (${formatBytes(data.before.size_bytes)})\n` +
                    `清理後: ${data.after.count} 筆 (${formatBytes(data.after.size_bytes)})`);

                // Reload logs to show updated data
                loadLogs();

            } catch (e) {
                console.error('Error cleaning up logs:', e);
                alert('清理請求失敗: ' + e.message);
            } finally {
                btn.disabled = false;
                btn.textContent = originalText;
                btn.style.opacity = '1';
            }
        }

        // ============================================================
        // Refresh Control
        // ============================================================
        function refreshAll() {
            document.getElementById('lastUpdate').textContent =
                '更新中...';

            Promise.all([
                loadSystemStatus(),
                loadMetrics(),
                loadLogs(),
                loadWorkerStatus()
            ]).then(() => {
                document.getElementById('lastUpdate').textContent =
                    '最後更新: ' + new Date().toLocaleTimeString('zh-TW');
            });
        }

        function toggleAutoRefresh() {
            autoRefresh = !autoRefresh;
            const btn = document.getElementById('autoRefreshBtn');

            if (autoRefresh) {
                btn.textContent = '自動更新: 開';
                btn.classList.add('active');
                startAutoRefresh();
            } else {
                btn.textContent = '自動更新: 關';
                btn.classList.remove('active');
                stopAutoRefresh();
            }
        }

        function startAutoRefresh() {
            if (refreshTimer) clearInterval(refreshTimer);
            refreshTimer = setInterval(refreshAll, REFRESH_INTERVAL);
        }

        function stopAutoRefresh() {
            if (refreshTimer) {
                clearInterval(refreshTimer);
                refreshTimer = null;
            }
        }

        // ============================================================
        // Utilities
        // ============================================================
        function escapeHtml(str) {
            if (!str) return '';
            const div = document.createElement('div');
            div.textContent = str;
            return div.innerHTML;
        }

        function formatTimestamp(ts) {
            if (!ts) return '--';
            try {
                const d = new Date(ts);
                return d.toLocaleString('zh-TW', {
                    month: '2-digit',
                    day: '2-digit',
                    hour: '2-digit',
                    minute: '2-digit',
                    second: '2-digit'
                });
            } catch (e) {
                return ts;
            }
        }

        function formatBytes(bytes) {
            if (!bytes || bytes === 0) return '0 B';
            const k = 1024;
            const sizes = ['B', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
        }

        // ============================================================
        // Initialize
        // ============================================================
        document.addEventListener('DOMContentLoaded', () => {
            initChart();
            refreshAll();
            startAutoRefresh();
        });

        // Refresh on visibility change
        document.addEventListener('visibilitychange', () => {
            if (!document.hidden && autoRefresh) {
                refreshAll();
            }
        });
    </script>
{% endblock %}
