        class IndexApp {
            constructor() {
                this.indexApiUrl = '/sandi/index';
                this.scheduleApiUrl = '/sandi/schedule';
                this.deleteApiUrl = '/sandi/delete';
                this.pendingDeleteAction = null;

                this.initializeEventListeners();
                this.setDefaultScheduleTime();
            }

            initializeEventListeners() {
                // Set default datetime to 5 seconds from now
                this.setDefaultScheduleTime();
            }

            setDefaultScheduleTime() {
                const now = new Date();
                now.setSeconds(now.getSeconds() + 5);
                const formatted = now.toISOString().slice(0, 16);
                document.getElementById('scheduledTime').value = formatted;
            }

            generateRequestId() {
                return 'index-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
            }

            // Tab switching
            switchTab(tabName) {
                // Hide all tabs
                document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active'));
                document.querySelectorAll('.nav-tab').forEach(tab => tab.classList.remove('active'));

                // Show selected tab
                document.getElementById(tabName).classList.add('active');
                event.target.classList.add('active');

                // Load data for the selected tab
                if (tabName === 'schedule') {
                    this.loadJobStats();
                    this.loadJobs();
                }
            }

            // Index Tab Functions
            async indexDocuments() {
                const clientId = document.getElementById('indexClientId').value.trim();
                const jsonText = document.getElementById('jsonDocuments').value.trim();

                if (!clientId) {
                    this.showError('Client ID is required');
                    return;
                }

                if (!jsonText) {
                    this.showError('JSON documents are required');
                    return;
                }

                let jsonData;
                try {
                    jsonData = JSON.parse(jsonText);
                    if (!Array.isArray(jsonData)) {
                        this.showError('JSON must be an array of documents');
                        return;
                    }
                } catch (error) {
                    this.showError('Invalid JSON format: ' + error.message);
                    return;
                }

                this.showLoading('index', true);
                this.clearMessages();

                const indexRequest = {
                    requestId: this.generateRequestId(),
                    clientId: clientId,
                    data: jsonData
                };

                try {
                    const response = await fetch(this.indexApiUrl, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(indexRequest)
                    });

                    const result = await response.json();

                    if (response.ok && result.status === 'SUCCESS') {
                        this.showSuccess(result.message + (result.indexed ? ` (${result.indexed} documents indexed)` : ''));
                        document.getElementById('jsonDocuments').value = '';
                    } else {
                        this.showError(result.message || 'Indexing failed');
                    }
                } catch (error) {
                    console.error('Index error:', error);
                    this.showError('Failed to connect to index API. Please check if the index API is running on port 8082.');
                } finally {
                    this.showLoading('index', false);
                }
            }

            // Schedule Tab Functions
            async scheduleJob() {
                const clientId = document.getElementById('scheduleClientId').value.trim();
                const jobId = document.getElementById('scheduleJobId').value.trim();
                const jobType = document.getElementById('jobType').value;
                const directory = document.getElementById('directory').value.trim();
                const fileExtensions = document.getElementById('fileExtensions').value.trim();
                const cronExpression = document.getElementById('cronExpression').value.trim();
                const scheduledTime = document.getElementById('scheduledTime').value;
                const forceReindexing = document.getElementById('forceReindexing').checked;
                const runNow = document.getElementById('runNow').checked;

                if (!clientId) {
                    this.showError('Client ID is required');
                    return;
                }

                if (!jobType) {
                    this.showError('Job type is required');
                    return;
                }

                if (!directory) {
                    this.showError('Directory or URL is required');
                    return;
                }

                if (!runNow && !scheduledTime) {
                    this.showError('Scheduled time is required');
                    return;
                }

                this.showLoading('schedule', true);
                this.clearMessages();

                const scheduleRequest = {
                    requestId: this.generateRequestId(),
                    clientId: clientId,
                    jobId: jobId || null,
                    jobType: jobType,
                    cron: cronExpression || null,
                    directory: directory,
                    fileExtensions: fileExtensions || null,
                    forceReindexing: forceReindexing
                };

                // Only add scheduledTime if Run Now is not checked
                if (!runNow) {
                    // Convert datetime-local format (yyyy-MM-ddThh:mm) to yyyy-MM-ddThh:mm:ss
                    scheduleRequest.scheduledTime = scheduledTime + ':00';
                }

                try {
                    const response = await fetch(`${this.scheduleApiUrl}/index`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(scheduleRequest)
                    });

                    const result = await response.json();

                    if (response.ok && (result.status === 'SUCCESS' || result.status === 'SCHEDULED')) {
                        this.showSuccess(result.message + (result.jobId ? ` (Job ID: ${result.jobId})` : ''));
                        this.resetScheduleForm();
                        this.loadJobs();
                        this.loadJobStats();
                    } else {
                        this.showError(result.message || 'Job scheduling failed');
                    }
                } catch (error) {
                    console.error('Schedule error:', error);
                    this.showError('Failed to connect to schedule API. Please check if the index API is running on port 8082.');
                } finally {
                    this.showLoading('schedule', false);
                }
            }

            resetScheduleForm() {
                document.getElementById('scheduleJobId').value = '';
                document.getElementById('jobType').value = '';
                document.getElementById('directory').value = '';
                document.getElementById('fileExtensions').value = '';
                document.getElementById('cronExpression').value = '';
                document.getElementById('forceReindexing').checked = false;
                document.getElementById('runNow').checked = false;
                this.setDefaultScheduleTime();
            }

            async loadJobs() {
                this.showLoading('schedule', true);

                try {
                    const response = await fetch(`${this.scheduleApiUrl}/jobs`);

                    if (response.ok) {
                        const jobs = await response.json();
                        this.displayJobs(jobs);
                    } else {
                        this.showError('Failed to load jobs');
                    }
                } catch (error) {
                    console.error('Load jobs error:', error);
                    this.showError('Failed to connect to schedule API.');
                } finally {
                    this.showLoading('schedule', false);
                }
            }

            displayJobs(jobs) {
                const container = document.getElementById('jobsTable');

                if (!jobs || jobs.length === 0) {
                    container.innerHTML = '<div class="no-data"><h3>No scheduled jobs found</h3><p>Create your first job using the form above</p></div>';
                    return;
                }

                let tableHtml = `
                    <div class="data-table">
                        <table class="table">
                            <thead>
                                <tr>
                                    <th>Job ID</th>
                                    <th>Client ID</th>
                                    <th>Type</th>
                                    <th>Directory</th>
                                    <th>Status</th>
                                    <th>Scheduled Time</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                `;

                jobs.forEach(job => {
                    const statusClass = `status-${job.status.toLowerCase()}`;
                    tableHtml += `
                        <tr>
                            <td><strong>${this.escapeHtml(job.jobId)}</strong></td>
                            <td>${this.escapeHtml(job.clientId)}</td>
                            <td>${this.escapeHtml(job.jobType)}</td>
                            <td>${this.escapeHtml(job.directory || '')}</td>
                            <td><span class="status-badge ${statusClass}">${job.status}</span></td>
                            <td>${job.scheduledTime ? new Date(job.scheduledTime).toLocaleString() : 'N/A'}</td>
                            <td class="actions-cell">
                                <button class="index-btn action-btn secondary" onclick="indexApp.viewJob('${job.jobId}')">View</button>
                                <button class="index-btn action-btn danger" onclick="indexApp.cancelJob('${job.jobId}')">Cancel</button>
                            </td>
                        </tr>
                    `;
                });

                tableHtml += '</tbody></table></div>';
                container.innerHTML = tableHtml;
            }

            async loadJobStats() {
                try {
                    const response = await fetch(`${this.scheduleApiUrl}/stats`);

                    if (response.ok) {
                        const stats = await response.json();
                        this.displayJobStats(stats);
                    }
                } catch (error) {
                    console.error('Load job stats error:', error);
                }
            }

            displayJobStats(stats) {
                const container = document.getElementById('jobStatsContainer');

                container.innerHTML = `
                    <div class="stats-grid">
                        <div class="stat-card">
                            <div class="stat-value">${stats.scheduled || 0}</div>
                            <div class="stat-label">Scheduled</div>
                        </div>
                        <div class="stat-card">
                            <div class="stat-value">${stats.running || 0}</div>
                            <div class="stat-label">Running</div>
                        </div>
                        <div class="stat-card">
                            <div class="stat-value">${stats.completed || 0}</div>
                            <div class="stat-label">Completed</div>
                        </div>
                    </div>
                `;
            }

            async viewJob(jobId) {
                try {
                    const response = await fetch(`${this.scheduleApiUrl}/jobs/${encodeURIComponent(jobId)}`);

                    if (response.ok) {
                        const job = await response.json();
                        alert(`Job Details:\nID: ${job.jobId}\nClient: ${job.clientId}\nType: ${job.jobType}\nDirectory: ${job.directory}\nStatus: ${job.status}\nScheduled: ${job.scheduledTime ? new Date(job.scheduledTime).toLocaleString() : 'N/A'}\nCreated: ${job.createdTime ? new Date(job.createdTime).toLocaleString() : 'N/A'}`);
                    } else {
                        this.showError('Failed to load job details');
                    }
                } catch (error) {
                    console.error('View job error:', error);
                    this.showError('Failed to load job details');
                }
            }

            async cancelJob(jobId) {
                if (!confirm(`Are you sure you want to cancel job "${jobId}"?`)) {
                    return;
                }

                try {
                    const response = await fetch(`${this.scheduleApiUrl}/jobs/${encodeURIComponent(jobId)}/cancel`, {
                        method: 'POST'
                    });

                    const result = await response.json();

                    if (response.ok && (result.status === 'SUCCESS' || result.status === 'CANCELLED')) {
                        this.showSuccess(result.message);
                        this.loadJobs();
                        this.loadJobStats();
                    } else {
                        this.showError(result.message || 'Failed to cancel job');
                    }
                } catch (error) {
                    console.error('Cancel job error:', error);
                    this.showError('Failed to cancel job');
                }
            }

            // Delete Tab Functions
            deleteDocuments(deleteType) {
                const clientId = document.getElementById('deleteClientId').value.trim();

                if (!clientId) {
                    this.showError('Client ID is required');
                    return;
                }

                let deleteRequest = {
                    requestId: this.generateRequestId(),
                    clientId: clientId
                };

                let details = '';

                if (deleteType === 'id') {
                    const id = document.getElementById('deleteById').value.trim();
                    if (!id) {
                        this.showError('Document ID is required');
                        return;
                    }
                    deleteRequest.id = id;
                    details = `<strong>Delete Type:</strong> By Document ID<br><strong>Client ID:</strong> ${this.escapeHtml(clientId)}<br><strong>Document ID:</strong> ${this.escapeHtml(id)}`;
                } else if (deleteType === 'ids') {
                    const idsText = document.getElementById('deleteByIds').value.trim();
                    if (!idsText) {
                        this.showError('List of IDs is required');
                        return;
                    }
                    try {
                        const ids = JSON.parse(idsText);
                        if (!Array.isArray(ids)) {
                            this.showError('IDs must be an array of strings');
                            return;
                        }
                        deleteRequest.ids = ids;
                        details = `<strong>Delete Type:</strong> By List of Document IDs<br><strong>Client ID:</strong> ${this.escapeHtml(clientId)}<br><strong>Document IDs:</strong> ${this.escapeHtml(JSON.stringify(ids))}<br><strong>Count:</strong> ${ids.length} documents`;
                    } catch (error) {
                        this.showError('Invalid JSON format for IDs: ' + error.message);
                        return;
                    }
                } else if (deleteType === 'query') {
                    const query = document.getElementById('deleteByQuery').value.trim();
                    if (!query) {
                        this.showError('Query is required');
                        return;
                    }
                    deleteRequest.query = query;
                    details = `<strong>Delete Type:</strong> By Solr Query<br><strong>Client ID:</strong> ${this.escapeHtml(clientId)}<br><strong>Query:</strong> ${this.escapeHtml(query)}`;
                }

                // Show confirmation dialog
                this.showConfirmationDialog(details, () => this.performDelete(deleteRequest, deleteType));
            }

            async performDelete(deleteRequest, deleteType) {
                this.showLoading('delete', true);
                this.clearMessages();

                try {
                    const response = await fetch(this.deleteApiUrl, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(deleteRequest)
                    });

                    const result = await response.json();

                    if (response.ok && result.status === 'SUCCESS') {
                        this.showSuccess(result.message);
                        // Clear the input fields
                        if (deleteType === 'id') {
                            document.getElementById('deleteById').value = '';
                        } else if (deleteType === 'ids') {
                            document.getElementById('deleteByIds').value = '';
                        } else if (deleteType === 'query') {
                            document.getElementById('deleteByQuery').value = '';
                        }
                    } else {
                        this.showError(result.message || 'Delete operation failed');
                    }
                } catch (error) {
                    console.error('Delete error:', error);
                    this.showError('Failed to connect to delete API. Please check if the index API is running on port 8082.');
                } finally {
                    this.showLoading('delete', false);
                }
            }

            // Utility methods
            showLoading(section, show) {
                document.getElementById(`${section}LoadingIndicator`).style.display = show ? 'block' : 'none';
            }

            showError(message) {
                document.getElementById('errorContainer').innerHTML = `
                    <div class="error">${this.escapeHtml(message)}</div>
                `;
                document.getElementById('successContainer').innerHTML = '';
            }

            showSuccess(message) {
                document.getElementById('successContainer').innerHTML = `
                    <div class="success">${this.escapeHtml(message)}</div>
                `;
                document.getElementById('errorContainer').innerHTML = '';
            }

            clearMessages() {
                document.getElementById('errorContainer').innerHTML = '';
                document.getElementById('successContainer').innerHTML = '';
            }

            escapeHtml(text) {
                const div = document.createElement('div');
                div.textContent = text;
                return div.innerHTML;
            }

            // Confirmation dialog methods
            showConfirmationDialog(details, confirmAction) {
                document.getElementById('confirmationDetails').innerHTML = details;
                this.pendingDeleteAction = confirmAction;
                document.getElementById('confirmationModal').style.display = 'block';

                // Focus on Cancel button by default for safety
                setTimeout(() => {
                    const cancelBtn = document.querySelector('#confirmationModal .index-btn.secondary');
                    if (cancelBtn) {
                        cancelBtn.focus();
                    }
                }, 100);
            }

            hideConfirmationModal() {
                document.getElementById('confirmationModal').style.display = 'none';
                this.pendingDeleteAction = null;
            }

            confirmDelete() {
                if (this.pendingDeleteAction) {
                    // Store the action before hiding modal (which clears it)
                    const actionToExecute = this.pendingDeleteAction;
                    this.hideConfirmationModal();

                    try {
                        actionToExecute();
                    } catch (error) {
                        this.showError('An error occurred while executing the delete operation');
                    }
                } else {
                    this.hideConfirmationModal();
                }
            }
        }

        // Global functions for tab switching
        function switchTab(tabName) {
            indexApp.switchTab(tabName);
        }

        function indexDocuments() {
            indexApp.indexDocuments();
        }

        function scheduleJob() {
            indexApp.scheduleJob();
        }

        function loadJobs() {
            indexApp.loadJobs();
        }

        function loadJobStats() {
            indexApp.loadJobStats();
        }

        function deleteDocuments(deleteType) {
            indexApp.deleteDocuments(deleteType);
        }

        function hideConfirmationModal() {
            indexApp.hideConfirmationModal();
        }

        function confirmDelete() {
            if (indexApp) {
                indexApp.confirmDelete();
            }
        }

        // Close modal when clicking outside
        document.addEventListener('click', (event) => {
            const confirmationModal = document.getElementById('confirmationModal');
            if (event.target === confirmationModal) {
                indexApp.hideConfirmationModal();
            }
        });

        // Add keyboard navigation for confirmation dialog
        document.addEventListener('keydown', (event) => {
            const confirmationModal = document.getElementById('confirmationModal');
            if (confirmationModal.style.display === 'block') {
                if (event.key === 'Escape') {
                    event.preventDefault();
                    indexApp.hideConfirmationModal();
                }
            }
        });

        // Initialize the index app
        const indexApp = new IndexApp();