<!-- htmlhint doctype-first:false -->
<!-- Observability Dashboard Partial -->
<script nonce="{{ csp_nonce(request) }}">
// Dark mode aware Chart.js defaults - shared across all observability charts
if (!window.getChartDefaults) {
  window.getChartDefaults = function() {
    const isDark = document.documentElement.classList.contains('dark');
    return {
      color: isDark ? '#e5e7eb' : '#374151',
      gridColor: isDark ? '#374151' : '#e5e7eb',
      titleColor: isDark ? '#f3f4f6' : '#1f2937',
      tickColor: isDark ? '#d1d5db' : '#6b7280',
    };
  };
}
/**
 * Execute <script> blocks from raw HTML text and return clean HTML.
 * Uses regex to extract scripts (avoids DOM innerHTML parsing issues)
 * and document.createElement('script') for reliable execution.
 */
window.__obsExecAndStrip = function(html) {
  var scriptRe = new RegExp('<' + 'script\\b([^>]*)>([\\s\\S]*?)</' + 'script>', 'gi');
  var m;
  while ((m = scriptRe.exec(html)) !== null) {
    var attrs = m[1];
    var code = m[2].trim();
    if (/(?:^|\s)src\s*=/i.test(attrs)) {
      console.warn('[obs] external <script src> not supported in dynamic partials, skipped');
      continue;
    }
    if (code) {
      try {
        var s = document.createElement('script');
        s.text = code;
        // Inherit nonce from parent document's HTMX config for CSP compliance
        var nonce = window.htmxConfig && window.htmxConfig.inlineScriptNonce;
        if (nonce) {
          s.setAttribute('nonce', nonce);
        }
        document.head.appendChild(s);
        s.remove();
      } catch (e) {
        console.error('[obs] script exec error:', e);
      }
    }
  }
  return html.replace(new RegExp('<' + 'script\\b[^>]*>[\\s\\S]*?</' + 'script>', 'gi'), '');
};</script>
<div class="observability-container" x-data="{
    viewMode: 'traces',
    selectedTrace: null,
    timeRange: '24h',
    statusFilter: 'all',
    minDuration: '',
    maxDuration: '',
    httpMethod: '',
    userEmail: '',
    nameSearch: '',
    attributeSearch: '',
    toolName: '',
    showAdvancedFilters: false,
    loading: false,
    stats: {},
    tracesInterval: null,
    statsInterval: null,
    savedQueries: [],
    selectedQueryId: '',
    showSaveQueryModal: false,
    saveQueryName: '',
    saveQueryDescription: '',
    saveQueryIsShared: false,
    metricsLoaded: false,
    toolsLoaded: false,
    promptsLoaded: false,
    resourcesLoaded: false,
    metricsLoading: false,
    toolsLoading: false,
    promptsLoading: false,
    resourcesLoading: false,
    async loadMetricsView() {
        // Only load once, but allow retry if previous load was interrupted
        if (this.metricsLoaded) {
            console.log('Metrics view already loaded, skipping fetch');
            return;
        }

        // Prevent concurrent loads
        if (this.metricsLoading) {
            console.log('Metrics view already loading, skipping');
            return;
        }

        this.metricsLoading = true;
        console.log('Loading metrics view for the first time...');

        try {
            const response = await fetch('{{ root_path }}/admin/observability/metrics/partial');
            if (response.ok) {
                // Check if still on metrics view before rendering
                if (this.viewMode !== 'metrics') {
                    console.log('View changed during fetch, aborting metrics load');
                    this.metricsLoading = false;
                    return;
                }

                const html = await response.text();
                const container = document.getElementById('metrics-container');
                if (!container) {
                    console.warn('Metrics container not found');
                    this.metricsLoading = false;
                    return;
                }

                // Extract scripts from raw text and execute synchronously,
                // then get clean HTML without <script> tags
                const cleanHtml = window.__obsExecAndStrip(html);

                // Insert script-free HTML with Alpine MutationObserver disabled,
                // then explicitly initialize Alpine components
                if (window.Alpine && typeof window.Alpine.mutateDom === 'function' && typeof window.Alpine.initTree === 'function') {
                    window.Alpine.mutateDom(() => {
                        container.innerHTML = cleanHtml;
                    });
                    window.Alpine.initTree(container);
                } else {
                    container.innerHTML = cleanHtml;
                }

                // Only mark as loaded if we're still on the metrics view
                if (this.viewMode === 'metrics') {
                    this.metricsLoaded = true;
                    console.log('Metrics view loaded successfully');
                } else {
                    console.log('View changed after render, not marking as loaded');
                }
            }
        } catch (error) {
            console.error('Failed to load metrics view:', error);
        } finally {
            this.metricsLoading = false;
        }
    },
    async loadToolsView() {
        // Only load once, but allow retry if previous load was interrupted
        if (this.toolsLoaded) {
            console.log('Tools view already loaded, skipping fetch');
            return;
        }

        // Prevent concurrent loads
        if (this.toolsLoading) {
            console.log('Tools view already loading, skipping');
            return;
        }

        this.toolsLoading = true;
        console.log('Loading tools view for the first time...');

        try {
            const response = await fetch('{{ root_path }}/admin/observability/tools/partial');
            if (response.ok) {
                // Check if still on tools view before rendering
                if (this.viewMode !== 'tools') {
                    console.log('View changed during fetch, aborting tools load');
                    this.toolsLoading = false;
                    return;
                }

                const html = await response.text();
                const container = document.getElementById('tools-container');
                if (!container) {
                    console.warn('Tools container not found');
                    this.toolsLoading = false;
                    return;
                }

                const cleanHtml = window.__obsExecAndStrip(html);

                if (window.Alpine && typeof window.Alpine.mutateDom === 'function' && typeof window.Alpine.initTree === 'function') {
                    window.Alpine.mutateDom(() => {
                        container.innerHTML = cleanHtml;
                    });
                    window.Alpine.initTree(container);
                } else {
                    container.innerHTML = cleanHtml;
                }

                // Only mark as loaded if we're still on the tools view
                if (this.viewMode === 'tools') {
                    this.toolsLoaded = true;
                    console.log('Tools view loaded successfully');
                } else {
                    console.log('View changed after render, not marking as loaded');
                }
            }
        } catch (error) {
            console.error('Failed to load tools view:', error);
        } finally {
            this.toolsLoading = false;
        }
    },
    async loadPromptsView() {
        // Only load once, but allow retry if previous load was interrupted
        if (this.promptsLoaded) {
            console.log('Prompts view already loaded, skipping fetch');
            return;
        }

        // Prevent concurrent loads
        if (this.promptsLoading) {
            console.log('Prompts view already loading, skipping');
            return;
        }

        this.promptsLoading = true;
        console.log('Loading prompts view for the first time...');

        try {
            const response = await fetch('{{ root_path }}/admin/observability/prompts/partial');
            if (response.ok) {
                // Check if still on prompts view before rendering
                if (this.viewMode !== 'prompts') {
                    console.log('View changed during fetch, aborting prompts load');
                    this.promptsLoading = false;
                    return;
                }

                const html = await response.text();
                const container = document.getElementById('prompts-container');
                if (!container) {
                    console.warn('Prompts container not found');
                    this.promptsLoading = false;
                    return;
                }

                const cleanHtml = window.__obsExecAndStrip(html);

                if (window.Alpine && typeof window.Alpine.mutateDom === 'function' && typeof window.Alpine.initTree === 'function') {
                    window.Alpine.mutateDom(() => {
                        container.innerHTML = cleanHtml;
                    });
                    window.Alpine.initTree(container);
                } else {
                    container.innerHTML = cleanHtml;
                }

                // Only mark as loaded if we're still on the prompts view
                if (this.viewMode === 'prompts') {
                    this.promptsLoaded = true;
                    console.log('Prompts view loaded successfully');
                } else {
                    console.log('View changed after render, not marking as loaded');
                }
            }
        } catch (error) {
            console.error('Failed to load prompts view:', error);
        } finally {
            this.promptsLoading = false;
        }
    },
    async loadResourcesView() {
        // Only load once, but allow retry if previous load was interrupted
        if (this.resourcesLoaded) {
            console.log('Resources view already loaded, skipping fetch');
            return;
        }

        // Prevent concurrent loads
        if (this.resourcesLoading) {
            console.log('Resources view already loading, skipping');
            return;
        }

        this.resourcesLoading = true;
        console.log('Loading resources view for the first time...');

        try {
            const response = await fetch('{{ root_path }}/admin/observability/resources/partial');
            if (response.ok) {
                // Check if still on resources view before rendering
                if (this.viewMode !== 'resources') {
                    console.log('View changed during fetch, aborting resources load');
                    this.resourcesLoading = false;
                    return;
                }

                const html = await response.text();
                const container = document.getElementById('resources-container');
                if (!container) {
                    console.warn('Resources container not found');
                    this.resourcesLoading = false;
                    return;
                }

                const cleanHtml = window.__obsExecAndStrip(html);

                if (window.Alpine && typeof window.Alpine.mutateDom === 'function' && typeof window.Alpine.initTree === 'function') {
                    window.Alpine.mutateDom(() => {
                        container.innerHTML = cleanHtml;
                    });
                    window.Alpine.initTree(container);
                } else {
                    container.innerHTML = cleanHtml;
                }

                // Only mark as loaded if we're still on the resources view
                if (this.viewMode === 'resources') {
                    this.resourcesLoaded = true;
                    console.log('Resources view loaded successfully');
                } else {
                    console.log('View changed after render, not marking as loaded');
                }
            }
        } catch (error) {
            console.error('Failed to load resources view:', error);
        } finally {
            this.resourcesLoading = false;
        }
    },
    refreshTraces() {
        let url = `{{ root_path }}/admin/observability/traces?time_range=${this.timeRange}&status_filter=${this.statusFilter}&limit=50`;
        if (this.minDuration) url += `&min_duration=${this.minDuration}`;
        if (this.maxDuration) url += `&max_duration=${this.maxDuration}`;
        if (this.httpMethod) url += `&http_method=${this.httpMethod}`;
        if (this.userEmail) url += `&user_email=${encodeURIComponent(this.userEmail)}`;
        if (this.nameSearch) url += `&name_search=${encodeURIComponent(this.nameSearch)}`;
        if (this.attributeSearch) url += `&attribute_search=${encodeURIComponent(this.attributeSearch)}`;
        if (this.toolName) url += `&tool_name=${encodeURIComponent(this.toolName)}`;
        htmx.ajax('GET', url, {target: '#traces-list', swap: 'innerHTML'});
    },
    refreshStats() {
        htmx.ajax('GET', '{{ root_path }}/admin/observability/stats', {target: '#stats-container', swap: 'innerHTML'});
    },
    startPolling() {
        this.refreshTraces();
        this.refreshStats();
        this.tracesInterval = setInterval(() => this.refreshTraces(), 5000);
        this.statsInterval = setInterval(() => this.refreshStats(), 30000);
    },
    stopPolling() {
        if (this.tracesInterval) clearInterval(this.tracesInterval);
        if (this.statsInterval) clearInterval(this.statsInterval);
    },
    applyFilters() {
        this.stopPolling();
        this.refreshTraces();
        this.startPolling();
    },
    async loadSavedQueries() {
        try {
            const response = await fetch('{{ root_path }}/admin/observability/queries');
            if (response.ok) {
                this.savedQueries = await response.json();
            }
        } catch (e) {
            console.error('Failed to load saved queries:', e);
        }
    },
    async applySavedQuery() {
        if (!this.selectedQueryId) return;
        try {
            const response = await fetch(`{{ root_path }}/admin/observability/queries/${this.selectedQueryId}`);
            if (response.ok) {
                const query = await response.json();
                const config = query.filter_config;
                this.timeRange = config.timeRange || '24h';
                this.statusFilter = config.statusFilter || 'all';
                this.minDuration = config.minDuration || '';
                this.maxDuration = config.maxDuration || '';
                this.toolName = config.toolName || '';
                this.httpMethod = config.httpMethod || '';
                this.userEmail = config.userEmail || '';
                this.nameSearch = config.nameSearch || '';
                this.attributeSearch = config.attributeSearch || '';
                this.applyFilters();
                // Track usage
                await fetch(`{{ root_path }}/admin/observability/queries/${this.selectedQueryId}/use`, { method: 'POST' });
            }
        } catch (e) {
            console.error('Failed to apply saved query:', e);
        }
    },
    getCurrentFilterConfig() {
        return {
            timeRange: this.timeRange,
            statusFilter: this.statusFilter,
            minDuration: this.minDuration,
            maxDuration: this.maxDuration,
            httpMethod: this.httpMethod,
            userEmail: this.userEmail,
            nameSearch: this.nameSearch,
            attributeSearch: this.attributeSearch,
            toolName: this.toolName
        };
    },
    async saveCurrentQuery() {
        if (!this.saveQueryName) {
            alert('Please enter a name for the query');
            return;
        }
        try {
            const response = await fetch('{{ root_path }}/admin/observability/queries', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    name: this.saveQueryName,
                    description: this.saveQueryDescription,
                    filter_config: this.getCurrentFilterConfig(),
                    is_shared: this.saveQueryIsShared
                })
            });
            if (response.ok) {
                this.showSaveQueryModal = false;
                this.saveQueryName = '';
                this.saveQueryDescription = '';
                this.saveQueryIsShared = false;
                await this.loadSavedQueries();
                alert('Query saved successfully!');
            } else {
                alert('Failed to save query');
            }
        } catch (e) {
            console.error('Failed to save query:', e);
            alert('Failed to save query');
        }
    },
    async deleteSavedQuery(queryId) {
        if (!confirm('Are you sure you want to delete this saved query?')) return;
        try {
            const response = await fetch(`{{ root_path }}/admin/observability/queries/${queryId}`, { method: 'DELETE' });
            if (response.ok) {
                await this.loadSavedQueries();
                if (this.selectedQueryId == queryId) {
                    this.selectedQueryId = '';
                }
            }
        } catch (e) {
            console.error('Failed to delete query:', e);
        }
    },
    resetLoadedFlags() {
        // Reset loaded flags so partials will reload when returning to the tab
        this.metricsLoaded = false;
        this.toolsLoaded = false;
        this.promptsLoaded = false;
        this.resourcesLoaded = false;
        console.log('Observability loaded flags reset');
    }
}" x-init="
    startPolling();
    loadSavedQueries();
    // Listen for tab leave event to reset state
    document.addEventListener('observability:leave', () => resetLoadedFlags());
    $watch('timeRange', () => applyFilters());
    $watch('statusFilter', () => applyFilters());
    $watch('minDuration', () => { if(minDuration) applyFilters(); });
    $watch('maxDuration', () => { if(maxDuration) applyFilters(); });
    $watch('httpMethod', () => applyFilters());
    $watch('userEmail', () => { if(userEmail) applyFilters(); });
    $watch('nameSearch', () => { if(nameSearch) applyFilters(); });
    $watch('attributeSearch', () => { if(attributeSearch) applyFilters(); });
    $watch('toolName', () => { if(toolName) applyFilters(); });
    $watch('selectedQueryId', () => { if(selectedQueryId) applySavedQuery(); });
">
    <style>
        /* Minimal styles for components that need precise positioning */
        .span-timeline {
            flex: 1;
            height: 24px;
            position: relative;
            margin: 0 0.5rem;
        }
        .span-bar {
            position: absolute;
            height: 100%;
            border-radius: 0.25rem;
            cursor: pointer;
            transition: opacity 0.2s;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .span-bar:hover {
            opacity: 0.8;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .critical-path-bar {
            box-shadow: 0 0 0 2px #f59e0b;
        }
        .time-marker {
            position: absolute;
            top: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
        }
    </style>

    <!-- Header -->
    <div class="mb-8 pb-4 border-b-2 border-gray-200 dark:border-gray-700">
        <!-- Title and Filters Row -->
        <div class="flex justify-between items-center mb-4 flex-wrap gap-4">
            <h2 class="text-3xl font-bold text-gray-900 dark:text-gray-100 flex items-center gap-2">
                <span>🔍</span>
                Observability Dashboard
            </h2>
            <div class="flex gap-4 items-center" x-show="viewMode === 'traces'">
            <select
                x-model="selectedQueryId"
                class="px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600"
                style="min-width: 200px;"
            >
                <option value="">📋 Saved Queries</option>
                <template x-for="query in savedQueries" :key="query.id">
                    <option :value="query.id" x-text="query.name + (query.is_shared ? ' (shared)' : '')"></option>
                </template>
            </select>
            <button
                class="px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600"
                @click="showSaveQueryModal = true"
                title="Save current filters as a query"
            >
                💾 Save Query
            </button>
            <select
                x-model="timeRange"
                class="px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600"
            >
                <option value="1h">Last Hour</option>
                <option value="6h">Last 6 Hours</option>
                <option value="24h" selected>Last 24 Hours</option>
                <option value="7d">Last 7 Days</option>
            </select>
            <select
                x-model="statusFilter"
                class="px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600"
            >
                <option value="all" selected>All Status</option>
                <option value="ok">Success Only</option>
                <option value="error">Errors Only</option>
            </select>
            <button
                class="px-4 py-2 text-sm border rounded-md cursor-pointer transition-all dark:border-gray-600 dark:hover:bg-gray-600"
                :class="showAdvancedFilters ? 'bg-blue-500 text-white border-blue-500 dark:bg-blue-600 dark:border-blue-500' : 'bg-white border-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100'"
                @click="showAdvancedFilters = !showAdvancedFilters"
            >
                ⚙️ Advanced Filters
            </button>
            <button
                class="px-4 py-2 text-sm bg-blue-500 text-white rounded-md cursor-pointer font-medium transition-colors hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-500"
                @click="refreshStats(); refreshTraces();"
            >
                🔄 Refresh
            </button>
            </div>
        </div>

        <!-- View Mode Tabs Row -->
        <div class="flex gap-2 flex-wrap">
            <button
                @click="viewMode = 'traces'"
                :class="viewMode === 'traces' ? 'bg-blue-500 text-white border-blue-500 dark:bg-blue-600 dark:border-blue-500' : 'bg-white border-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600'"
                class="px-4 py-2 text-sm border rounded-md cursor-pointer transition-all"
            >
                📋 Traces
            </button>
            <button
                @click="viewMode = 'metrics'; loadMetricsView()"
                :class="viewMode === 'metrics' ? 'bg-blue-500 text-white border-blue-500 dark:bg-blue-600 dark:border-blue-500' : 'bg-white border-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600'"
                class="px-4 py-2 text-sm border rounded-md cursor-pointer transition-all"
            >
                📊 Advanced Metrics
            </button>
            <button
                @click="viewMode = 'tools'; loadToolsView()"
                :class="viewMode === 'tools' ? 'bg-blue-500 text-white border-blue-500 dark:bg-blue-600 dark:border-blue-500' : 'bg-white border-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600'"
                class="px-4 py-2 text-sm border rounded-md cursor-pointer transition-all"
            >
                🔧 MCP Tools
            </button>
            <button
                @click="viewMode = 'prompts'; loadPromptsView()"
                :class="viewMode === 'prompts' ? 'bg-blue-500 text-white border-blue-500 dark:bg-blue-600 dark:border-blue-500' : 'bg-white border-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600'"
                class="px-4 py-2 text-sm border rounded-md cursor-pointer transition-all"
            >
                💬 Prompts
            </button>
            <button
                @click="viewMode = 'resources'; loadResourcesView()"
                :class="viewMode === 'resources' ? 'bg-blue-500 text-white border-blue-500 dark:bg-blue-600 dark:border-blue-500' : 'bg-white border-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600'"
                class="px-4 py-2 text-sm border rounded-md cursor-pointer transition-all"
            >
                📦 Resources
            </button>
        </div>
    </div>

    <!-- Traces View -->
    <div x-show="viewMode === 'traces'">
    <!-- Advanced Filters Panel -->
    <div x-show="showAdvancedFilters"
         x-transition
         class="bg-white dark:bg-gray-800 rounded-lg p-6 mb-6 shadow-sm dark:shadow-gray-900/30">
        <h3 class="m-0 mb-4 text-lg font-semibold text-gray-700 dark:text-gray-200">
            🔧 Advanced Filters
        </h3>
        <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;">
            <!-- Duration Range -->
            <div>
                <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    Min Duration (ms)
                </label>
                <input
                    type="number"
                    x-model="minDuration"
                    placeholder="e.g., 100"
                    class="w-full px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:placeholder-gray-400"
                    @change="refreshTraces()"
                />
            </div>
            <div>
                <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    Max Duration (ms)
                </label>
                <input
                    type="number"
                    x-model="maxDuration"
                    placeholder="e.g., 5000"
                    class="w-full px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:placeholder-gray-400"
                    @change="refreshTraces()"
                />
            </div>

            <!-- HTTP Method -->
            <div>
                <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    HTTP Method
                </label>
                <select
                    x-model="httpMethod"
                    class="w-full px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600"
                    @change="refreshTraces()"
                >
                    <option value="">All Methods</option>
                    <option value="GET">GET</option>
                    <option value="POST">POST</option>
                    <option value="PUT">PUT</option>
                    <option value="DELETE">DELETE</option>
                    <option value="PATCH">PATCH</option>
                </select>
            </div>

            <!-- User Email -->
            <div>
                <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    User Email
                </label>
                <input
                    type="text"
                    x-model="userEmail"
                    placeholder="admin@example.com"
                    class="w-full px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:placeholder-gray-400"
                    @input.debounce.500ms="refreshTraces()"
                />
            </div>

            <!-- Name Search -->
            <div>
                <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    Trace Name
                </label>
                <input
                    type="text"
                    x-model="nameSearch"
                    placeholder="e.g., GET /api/tools"
                    class="w-full px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:placeholder-gray-400"
                    @input.debounce.500ms="refreshTraces()"
                />
            </div>

            <!-- Attribute Search -->
            <div>
                <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    Attribute Search
                </label>
                <input
                    type="text"
                    x-model="attributeSearch"
                    placeholder="Search in attributes..."
                    class="w-full px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:placeholder-gray-400"
                    @input.debounce.500ms="refreshTraces()"
                />
            </div>

            <!-- Tool Name Filter -->
            <div>
                <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                    🔧 MCP Tool Name
                </label>
                <input
                    type="text"
                    x-model="toolName"
                    placeholder="Filter by tool name..."
                    class="w-full px-4 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:placeholder-gray-400"
                    @input.debounce.500ms="refreshTraces()"
                />
            </div>
        </div>

        <!-- Clear Filters Button -->
        <div class="mt-4 text-right">
            <button
                class="px-6 py-2 text-sm border border-gray-300 rounded-md bg-white hover:bg-gray-50 cursor-pointer transition-all dark:bg-gray-700 dark:text-gray-100 dark:border-gray-600 dark:hover:bg-gray-600"
                @click="minDuration=''; maxDuration=''; httpMethod=''; userEmail=''; nameSearch=''; attributeSearch=''; refreshTraces();"
            >
                🗑️ Clear All Filters
            </button>
        </div>
    </div>

    <!-- Statistics Cards -->
    <div id="stats-container">
        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
            <div class="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm dark:shadow-gray-900/30 border-l-4 border-blue-500">
                <div class="text-sm text-gray-600 dark:text-gray-400 mb-2">Loading statistics...</div>
            </div>
        </div>
    </div>

    <!-- Traces Table -->
    <div class="w-full bg-white dark:bg-gray-800 rounded-lg shadow-sm dark:shadow-gray-900/30 overflow-hidden">
        <table class="w-full border-collapse">
            <thead>
                <tr>
                    <th class="bg-gray-50 dark:bg-gray-700/50 px-4 py-3 text-left text-sm font-semibold text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">Timestamp</th>
                    <th class="bg-gray-50 dark:bg-gray-700/50 px-4 py-3 text-left text-sm font-semibold text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">Method</th>
                    <th class="bg-gray-50 dark:bg-gray-700/50 px-4 py-3 text-left text-sm font-semibold text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">Endpoint</th>
                    <th class="bg-gray-50 dark:bg-gray-700/50 px-4 py-3 text-left text-sm font-semibold text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">Status</th>
                    <th class="bg-gray-50 dark:bg-gray-700/50 px-4 py-3 text-left text-sm font-semibold text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">Duration</th>
                    <th class="bg-gray-50 dark:bg-gray-700/50 px-4 py-3 text-left text-sm font-semibold text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">User</th>
                    <th class="bg-gray-50 dark:bg-gray-700/50 px-4 py-3 text-left text-sm font-semibold text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700">Actions</th>
                </tr>
            </thead>
            <tbody id="traces-list">
                <tr>
                    <td colspan="7" class="text-center py-8 text-gray-500 dark:text-gray-400">
                        Loading traces...
                    </td>
                </tr>
            </tbody>
        </table>
    </div>

    <!-- Trace Detail Modal (shown when trace is selected) -->
    <div x-show="selectedTrace"
         x-cloak
         class="fixed inset-0 bg-black/50 dark:bg-black/70 flex items-center justify-center z-[1000]"
         @click.self="selectedTrace = null">
        <div class="bg-white dark:bg-gray-800 rounded-lg max-w-[90%] max-h-[90%] overflow-auto shadow-2xl" id="trace-detail-content">
            <!-- Loaded via HTMX -->
        </div>
    </div>

    <!-- Save Query Modal -->
    <div x-show="showSaveQueryModal"
         x-cloak
         class="fixed inset-0 bg-black/50 dark:bg-black/70 flex items-center justify-center z-[1000]"
         @click.self="showSaveQueryModal = false">
        <div class="bg-white dark:bg-gray-800 rounded-lg max-w-2xl w-full mx-4 p-8 shadow-2xl">
            <div class="flex justify-between items-center mb-6 pb-4 border-b border-gray-200 dark:border-gray-700">
                <h3 class="text-2xl font-bold text-gray-900 dark:text-gray-100 m-0">💾 Save Query</h3>
                <button @click="showSaveQueryModal = false" class="bg-transparent border-0 text-2xl cursor-pointer text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100">×</button>
            </div>

            <div class="flex flex-col gap-6">
                <!-- Query Name -->
                <div>
                    <label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
                        Query Name <span class="text-red-500">*</span>
                    </label>
                    <input
                        x-model="saveQueryName"
                        type="text"
                        placeholder="e.g., Slow Requests Last Hour"
                        class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400"
                    />
                </div>

                <!-- Query Description -->
                <div>
                    <label class="block text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
                        Description (optional)
                    </label>
                    <textarea
                        x-model="saveQueryDescription"
                        placeholder="What does this query help you find?"
                        rows="3"
                        class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 resize-y focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400"
                    ></textarea>
                </div>

                <!-- Share with Team -->
                <div class="flex items-center gap-2">
                    <input
                        x-model="saveQueryIsShared"
                        type="checkbox"
                        id="save-query-shared"
                        class="w-4 h-4 text-blue-600 border-gray-300 dark:border-gray-600 rounded focus:ring-2 focus:ring-blue-500 dark:bg-gray-700"
                    />
                    <label for="save-query-shared" class="text-sm font-medium text-gray-700 dark:text-gray-300 cursor-pointer">
                        Share with team (visible to all users)
                    </label>
                </div>

                <!-- Current Filters Preview -->
                <div class="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4">
                    <p class="text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2 uppercase">Current Filters</p>
                    <div class="grid grid-cols-2 gap-2 text-sm text-gray-700 dark:text-gray-300">
                        <div x-show="timeRange"><strong>Time:</strong> <span x-text="timeRange"></span></div>
                        <div x-show="statusFilter"><strong>Status:</strong> <span x-text="statusFilter"></span></div>
                        <div x-show="minDuration"><strong>Min Duration:</strong> <span x-text="minDuration + 'ms'"></span></div>
                        <div x-show="maxDuration"><strong>Max Duration:</strong> <span x-text="maxDuration + 'ms'"></span></div>
                        <div x-show="httpMethod"><strong>HTTP Method:</strong> <span x-text="httpMethod"></span></div>
                        <div x-show="userEmail"><strong>User:</strong> <span x-text="userEmail"></span></div>
                        <div x-show="nameSearch" class="col-span-2"><strong>Name:</strong> <span x-text="nameSearch"></span></div>
                        <div x-show="attributeSearch" class="col-span-2"><strong>Attributes:</strong> <span x-text="attributeSearch"></span></div>
                    </div>
                </div>

                <!-- Action Buttons -->
                <div class="flex justify-end gap-4 pt-4 border-t border-gray-200 dark:border-gray-700">
                    <button
                        @click="showSaveQueryModal = false"
                        class="px-6 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-md cursor-pointer font-medium hover:bg-gray-50 dark:hover:bg-gray-600 transition-colors"
                    >
                        Cancel
                    </button>
                    <button
                        @click="saveCurrentQuery()"
                        class="px-6 py-2 bg-blue-600 dark:bg-blue-500 text-white rounded-md cursor-pointer font-medium hover:bg-blue-700 dark:hover:bg-blue-600 transition-colors"
                    >
                        Save Query
                    </button>
                </div>
            </div>
        </div>
    </div>
    </div> <!-- End Traces View -->

    <!-- Metrics View -->
    <div x-show="viewMode === 'metrics'" id="metrics-container">
        <div class="p-8 text-center text-gray-600 dark:text-gray-400">
            Loading metrics dashboard...
        </div>
    </div>

    <!-- Tools View -->
    <div x-show="viewMode === 'tools'" id="tools-container">
        <div class="p-8 text-center text-gray-600 dark:text-gray-400">
            Loading tool metrics dashboard...
        </div>
    </div>

    <!-- Prompts View -->
    <div x-show="viewMode === 'prompts'" id="prompts-container">
        <div class="p-8 text-center text-gray-600 dark:text-gray-400">
            Loading prompt metrics dashboard...
        </div>
    </div>

    <!-- Resources View -->
    <div x-show="viewMode === 'resources'" id="resources-container">
        <div class="p-8 text-center text-gray-600 dark:text-gray-400">
            Loading resource metrics dashboard...
        </div>
    </div>
</div>
