/**
 * Offline/Online Sync Manager for NCS Billing System
 * Tracks transactions done offline and syncs when internet is restored
 */
(function() {
    'use strict';
    var DEBUG = window.OFFLINE_SYNC_DEBUG === true;
    function log() { if (DEBUG) console.log.apply(console, arguments); }

    const OfflineSyncManager = {
        // Configuration
        config: {
            get syncUrl() {
                return (window.baseURL || '') + 'sync/auto_sync';
            },
            get statusUrl() {
                return (window.baseURL || '') + 'sync/status';
            },
            offlineQueueKey: 'offline_transactions_queue',
            lastSyncKey: 'last_sync_time',
            checkInterval: 10000, // Check every 1.5 seconds for immediate detection
            autoSyncDelay: 800  // Short delay before auto-sync after coming online
        },

        // State
        isOnline: navigator.onLine,
        syncInProgress: false,
        queue: [],
        initialized: false, // Track if already initialized

        /**
         * Initialize
         */
        init: function() {
            // Only run on POS page (where the connection badge exists)
            if (!document.getElementById('connection-status-badge-pos')) {
                log('OfflineSync: Not on POS page, skipping init');
                return;
            }
            // Prevent multiple initializations
            if (this.initialized) {
                log('OfflineSync: Already initialized, skipping...');
                return;
            }
            
            log('OfflineSync: Initializing (POS page)...');
            this.initialized = true;
            
            // Ensure baseURL is initialized once
if (!window.baseURL) {

    window.baseURL =
        window.baseURL ||
        window.base_url ||
        $('base').attr('href') ||
        $('#base_url').val() ||
        window.location.origin + "/";

    if (!window.baseURL.endsWith('/')) {
        window.baseURL += '/';
    }
}
            
            // Only localhost/127.0.0.1 = no offline UI; any other host (including 192.168.x) = show icon and detect offline
            var isLocalInstallation = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
            
            this.loadQueue();
            
            // Check if any transactions are missing URLs and try to migrate them
            const needsMigration = this.queue.some(t => !t.url && t.type === 'sale');
            if (needsMigration) {
                log('OfflineSync: Found transactions without URLs, migrating...');
                this.queue.forEach(t => {
                    if (!t.url && t.type === 'sale') {
                        t.url = this.reconstructPosUrl(t.data);
                    }
                });
                this.saveQueue();
            }
            
            // On localhost: no internet needed, treat as always online (no sync/offline UI)
            // When deployed online: respect browser offline/online and run auto-sync when connection restored
            if (isLocalInstallation) {
                log('OfflineSync: Local installation - no internet/sync needed');
                this.isOnline = true;
            } else {
                this.isOnline = navigator.onLine;
                this.setupAjaxInterceptor();
            }
            
            // Event listeners and connection checking (offline event ignored on localhost below)
            this.setupEventListeners();
            this.startConnectionCheck();
            this.updateStatusIndicator();
            // Run first connection check immediately (don't wait for interval)
            if (!isLocalInstallation) {
                var self = this;
                setTimeout(function() { self.checkConnection(); }, 100);
                // Fast poll navigator.onLine so icon switches to offline within ~400ms (browser events can be delayed)
                this.fastOfflineCheckInterval = setInterval(function() {
                    if (!navigator.onLine && self.isOnline) {
                        self.isOnline = false;
                        self.updateStatusIndicator();
                        log('OfflineSync: Fast poll - navigator.onLine false, marked offline');
                    }
                }, 400);
            }
            
            // If online and have queued items, trigger auto-sync immediately
            if (this.isOnline && this.queue.length > 0) {
                log('OfflineSync: Online with', this.queue.length, 'queued items - triggering auto-sync');
                setTimeout(() => this.attemptAutoSync(), this.config.autoSyncDelay);
            }
        },

        /**
         * Setup event listeners
         */
        setupEventListeners: function() {
            // Store reference to this for use in event listeners
            const self = this;
            
            window.addEventListener('online', function() {
                log('OfflineSync: Browser reports online - update UI immediately');
                var wasOffline = !self.isOnline;
                // Update UI immediately so user sees green icon right away
                self.isOnline = true;
                self.updateStatusIndicator();
                // Verify in background (if server unreachable we'll correct state on next check)
                self.verifyConnection().then(function(result) {
                    log('OfflineSync: Verification result:', result);
                    if (!result.online) {
                        self.isOnline = false;
                        self.updateStatusIndicator();
                        return;
                    }
                    if (wasOffline && self.queue.length > 0 && !self.syncInProgress) {
                        log('OfflineSync: Internet restored! Auto-syncing', self.queue.length, 'queued items');
                        setTimeout(function() { self.attemptAutoSync(); }, self.config.autoSyncDelay);
                    } else if (self.queue.length > 0 && !self.syncInProgress) {
                        setTimeout(function() { self.attemptAutoSync(); }, self.config.autoSyncDelay);
                    }
                }).catch(function(error) {
                    console.error('OfflineSync: Verification error:', error);
                    if (self.queue.length > 0 && !self.syncInProgress) {
                        setTimeout(function() { self.attemptAutoSync(); }, self.config.autoSyncDelay * 2);
                    }
                });
            });

            window.addEventListener('offline', function() {
                log('OfflineSync: Connection lost - update UI immediately');
                var isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
                if (isLocal) {
                    log('OfflineSync: Local - ignoring offline event');
                    return;
                }
                self.isOnline = false;
                self.updateStatusIndicator();
            });

            // Track when transactions are made
            document.addEventListener('transactionCompleted', (e) => {
                this.handleTransaction(e.detail);
            });

            // Note: setupAjaxInterceptor is now called conditionally in init()
            // Only for non-local installations
        },

        /**
         * Setup AJAX interceptor to catch failed requests
         * Only called for non-local installations
         */
        setupAjaxInterceptor: function() {
            // Save original send method
            const originalSend = XMLHttpRequest.prototype.send;
            const self = this;

            XMLHttpRequest.prototype.send = function(data) {
                var xhr = this;
                this.addEventListener('error', function() {
                    // Network failure (status 0) = go offline immediately so icon updates
                    if (xhr.status === 0 || xhr.readyState === 4 && xhr.status === 0) {
                        var isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
                        if (!isLocal && self.isOnline) {
                            self.isOnline = false;
                            self.updateStatusIndicator();
                            log('OfflineSync: XHR failed (network) - marked offline immediately');
                        }
                    }
                });

                this.addEventListener('load', function() {
                    if (this.status >= 200 && this.status < 400) {
                        // Request succeeded
                    }
                });

                // Call original send
                originalSend.call(this, data);
            };
        },

        /**
         * Start periodic connection check
         */
        startConnectionCheck: function() {
            const self = this;
            // Store interval ID so we can clear it if needed
            if (this.connectionCheckInterval) {
            clearInterval(this.connectionCheckInterval);
        }

            this.connectionCheckInterval = setInterval(() => {
             self.checkConnection();
            }, self.config.checkInterval);
            log('OfflineSync: Started periodic connection check (every', self.config.checkInterval, 'ms)');
        },

        /**
         * Check connection status - actually verify connection by pinging server
         */
        checkConnection: function() {
            // Only localhost/127.0.0.1 = no internet needed; 192.168.x and others = show offline icon and sync
            var isLocalInstallation = window.location.hostname === 'localhost' || 
                                     window.location.hostname === '127.0.0.1';

            // When deployed: if browser says offline, update immediately (icon + state) so UI reflects it even if 'offline' event didn't fire
            if (!isLocalInstallation && !navigator.onLine) {
                if (this.isOnline) {
                    this.isOnline = false;
                    this.updateStatusIndicator();
                    log('OfflineSync: navigator.onLine false - marked offline');
                }
                return;
            }

            // For local installations, always consider online
            if (isLocalInstallation) {
                if (!this.isOnline) {
                    this.isOnline = true;
                    this.updateStatusIndicator();
                }
                // Always try to sync if there are queued items (even on local)
                if (this.queue.length > 0 && !this.syncInProgress) {
                setTimeout(() => this.attemptAutoSync(), this.config.autoSyncDelay);
                }
                return;
            }
            
            // For non-local: ALWAYS ping server so icon turns red when offline (navigator.onLine can stay true)
            this.verifyConnection().then(function(result) {
                log('OfflineSync: checkConnection verification complete:', result);
            }).catch(function(error) {
                console.error('OfflineSync: Error in checkConnection verifyConnection:', error);
                if (this.isOnline && this.queue.length > 0 && !this.syncInProgress) {
                    setTimeout(function() { this.attemptAutoSync(); }.bind(this), this.config.autoSyncDelay);
                }
            }.bind(this));
        },
        
        /**
         * Verify connection by actually pinging the server
         */
        verifyConnection: function() {
            // Ensure baseURL is set before making request
            if (!window.baseURL) {
                window.baseURL = typeof base_url !== 'undefined' ? base_url : (document.getElementById('base_url') ? document.getElementById('base_url').value : '');
                if (!window.baseURL) {
                    log('OfflineSync: window.baseURL not set; assuming online (POS page may still be loading).');
                    // Don't mark offline when we simply can't ping - leave state unchanged
                    return Promise.resolve({ online: this.isOnline });
                }
                log('OfflineSync: baseURL set in verifyConnection:', window.baseURL);
            }
            
            // Use a lightweight endpoint to check connectivity
            // Always use a fresh URL to avoid browser caching
            const pingUrl = this.config.statusUrl +
                (this.config.statusUrl.indexOf('?') === -1 ? '?' : '&') +
                      '_=' + Date.now();
            
            // Create a timeout for the ping (2s so detection feels immediate)
            const timeout = new Promise((resolve) => {
                setTimeout(() => {

    resolve({
        online: navigator.onLine,
        timeout: true
    });

}, 5000);
            });
            
            // Create the actual ping request
            // Use a simple approach: if we can reach the server (even with error), we're online
            const ping = fetch(pingUrl, {
    method: 'GET',
    cache: 'no-store',
    credentials: 'same-origin',
    keepalive: true,
    headers: {
        'Cache-Control': 'no-cache, no-store, must-revalidate',
        'Pragma': 'no-cache',
        'Expires': '0',
        'X-Requested-With': 'XMLHttpRequest'
    }
})
            .then(response => {
                // Any response (even error) means we're online - server is reachable
                log('OfflineSync: Ping response status:', response.status, response.statusText);
                // If we get ANY response, the server is reachable = we're online
                // Status 0 might be CORS issue but still means server responded
                if (response.ok || response.status < 500 || response.status === 0) {
                    return { online: true };
                }
                // Even 404/403 means server is reachable (just endpoint/auth issue)
                if (response.status >= 400 && response.status < 500) {
                    return { online: true }; // Server is reachable, just endpoint issue
                }
                return { online: false };
            })
            .catch(error => {
                log('OfflineSync: Ping failed:', error.message || error);
                // Network error (TypeError: Failed to fetch) means offline
                // But if error is something else, might still be online
                if (error.name === 'TypeError' && error.message.includes('fetch')) {
                    return { online: false }; // Network error = offline
                }
                // Other errors might mean server is reachable but had issues
                return { online: false };
            });
            
            // Race between ping and timeout - return promise for chaining
            return Promise.race([ping, timeout])
                .then(result => {
                    const wasOffline = !self.isOnline;
                    // Timeout or transient failure: don't mark offline (avoid false "offline" when server is slow)
                    if (result.timeout) {
                        log('OfflineSync: Ping timed out; keeping current state:', self.isOnline);
                        return result;
                    }
                    self.isOnline = result.online;
                    
                    log('OfflineSync: verifyConnection result - wasOffline:', wasOffline, 'nowOnline:', self.isOnline, 'queueLength:', self.queue.length);
                    
                    // If we just came back online, trigger sync immediately
                    if (wasOffline && self.isOnline) {
                        log('OfflineSync: Connection restored via ping check!');
                        self.updateStatusIndicator();
                        if (self.queue.length > 0 && !self.syncInProgress) {
                            log('OfflineSync: Internet restored! Auto-syncing', self.queue.length, 'queued items');
                            // Trigger sync immediately when connection is restored
                            setTimeout(() => {
                                log('OfflineSync: Executing auto-sync now (connection restored)...');
                                self.attemptAutoSync();
                            }, self.config.autoSyncDelay);
                        } else {
                            log('OfflineSync: Connection restored but no items to sync or sync in progress');
                        }
                    } else if (self.isOnline && self.queue.length > 0 && !self.syncInProgress) {
                        // If we're online and have pending items, try to sync
                        log('OfflineSync: Online with pending items, triggering auto-sync');
                        setTimeout(() => {
                            log('OfflineSync: Executing auto-sync for pending items...');
                            self.attemptAutoSync();
                        }, self.config.autoSyncDelay);
                    } else if (self.isOnline && self.queue.length === 0) {
                        // Online and no pending items - just update indicator
                        self.updateStatusIndicator();
                    } else if (!self.isOnline) {
                        // Update indicator if we're still offline
                        self.updateStatusIndicator();
                    }
                    
                    return result;
                })
                .catch(error => {

    console.warn('OfflineSync: Connection check failed', error);

    // Only mark offline when browser itself says offline
    if (!navigator.onLine) {
        self.isOnline = false;
        self.updateStatusIndicator();
    }

    return {
        online: navigator.onLine
    };
});
        },

        /**
         * Handle completed transaction
         * This is called when a transaction completes successfully
         */
        handleTransaction: function(transactionData) {
            // Transaction already saved successfully
            // Just log it - no need to queue
            log('OfflineSync: Transaction completed', transactionData);
            
            // The transaction was already saved by the server
            // We only queue if the save failed (handled elsewhere)
        },

        /**
         * Queue a failed transaction for later sync
         */
        queueFailedTransaction: function(transactionData) {
            const transaction = {
                id: this.generateId(),
                type: transactionData.type, // 'sale', 'purchase', 'return', etc.
                data: transactionData.data,
                url: transactionData.url, // Store the URL for syncing
                timestamp: new Date().toISOString(),
                synced: false
            };

            this.queue.push(transaction);
            this.saveQueue();
            this.updateStatusIndicator();
            
            log('OfflineSync: Transaction queued for retry', transaction);
            log('OfflineSync: Transaction URL stored:', transaction.url);
            
            // Try to sync if online
            if (this.isOnline) {
                setTimeout(() => this.attemptAutoSync(), this.config.autoSyncDelay);
            }
        },

        /**
         * Generate unique ID for transaction
         */
        generateId: function() {
            return 'offline_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
        },

        /**
         * Update status indicator - updates all badge and pending-count elements
         */
        updateStatusIndicator: function() {
            const badges = document.querySelectorAll('#connection-status-badge, #connection-status-badge-pos');
            const countLeft = document.getElementById('pending-count-left');
            const countPos = document.getElementById('pending-count-pos');
            const countElements = [countLeft, countPos].filter(Boolean);

            const titleOnline = this.queue.length > 0
                ? (this.queue.length + ' transaction(s) pending sync - Click to sync')
                : 'Online - All transactions synced';
            const titleOffline = this.queue.length > 0
                ? (this.queue.length + ' pending - Working offline. Will sync when connection is restored.')
                : 'Offline - Transactions will sync when connection is restored.';

            badges.forEach(function(badge) {
                badge.style.display = 'inline-block';
                badge.style.visibility = 'visible';
                if (this.isOnline) {
                    badge.style.background = '#28a745';
                    badge.style.animation = 'none';
                    badge.title = titleOnline;
                } else {
                    badge.style.background = '#dc3545';
                    badge.style.animation = 'pulse 2s infinite';
                    badge.title = titleOffline;
                }
            }.bind(this));

            countElements.forEach(function(el) {
                if (this.queue.length > 0) {
                    el.textContent = this.queue.length;
                    el.style.display = 'block';
                    el.style.background = this.isOnline ? '#ff6b6b' : '#ffa500';
                } else {
                    el.style.display = 'none';
                }
            }.bind(this));
        },

        /**
         * Load queue from localStorage
         */
        loadQueue: function() {
            try {
                const stored = localStorage.getItem(this.config.offlineQueueKey);
                if (stored) {
                    this.queue = JSON.parse(stored).filter(t => !t.synced);
                    log('OfflineSync: Loaded', this.queue.length, 'pending transactions');
                }
            } catch (e) {
                console.error('OfflineSync: Failed to load queue', e);
                this.queue = [];
            }
        },

        /**
         * Save queue to localStorage
         */
        saveQueue: function() {
            try {
                localStorage.setItem(this.config.offlineQueueKey, JSON.stringify(this.queue));
            } catch (e) {
                console.error('OfflineSync: Failed to save queue', e);
            }
        },

        /**
         * Attempt auto-sync
         */
        attemptAutoSync: function() {
            // Check conditions
            if (this.syncInProgress) {
                log('OfflineSync: Sync already in progress, skipping...');
                return;
            }
            
            if (this.queue.length === 0) {
                log('OfflineSync: No queued items to sync');
                return;
            }
            
            // For local installations, always allow sync
            var isLocalInstallation = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';

            if (!isLocalInstallation && !this.isOnline) {
                log('OfflineSync: Not online, cannot sync');
                return;
            }

            log('OfflineSync: Attempting auto-sync with', this.queue.length, 'items...');
            this.performSync();
        },

        /**
         * Perform synchronization
         */
        performSync: function() {
            if (this.syncInProgress) {
                log('OfflineSync: Sync already in progress');
                return;
            }

            this.syncInProgress = true;
            const unsynced = this.queue.filter(t => !t.synced);
            
            log('OfflineSync: Starting sync of', unsynced.length, 'unsynced transactions');
            this.showSyncProgress('Syncing ' + unsynced.length + ' transactions...');

            if (unsynced.length === 0) {
                this.syncInProgress = false;
                this.showSyncNotification('No pending transactions to sync', 'info');
                return;
            }

            // Sync each transaction
            this.syncTransactions(unsynced, 0);
        },

        /**
         * Sync transactions one by one
         */
        syncTransactions: function(transactions, index, failedCount = 0) {
            if (index >= transactions.length) {
                // All processed
                const syncedCount = transactions.filter(t => t.synced).length;
                const failed = transactions.filter(t => !t.synced).length;
                this.markAllSynced();
                this.syncInProgress = false;
                
                if (failed === 0) {
                    this.showSyncNotification(`${syncedCount} transaction(s) synced successfully!`, 'success');
                } else {
                    this.showSyncNotification(`${syncedCount} synced, ${failed} failed. Review failed transactions.`, 'error');
                }
                this.updateStatusIndicator();
                return;
            }

            const transaction = transactions[index];
            log('OfflineSync: Syncing transaction', index + 1, 'of', transactions.length);
            
            this.syncSingleTransaction(transaction)
                .then(() => {
                    log('OfflineSync: Transaction', index + 1, 'synced successfully');
                    transaction.synced = true;
                    this.saveQueue();
                    this.updateStatusIndicator();
                    
                    // Continue with next transaction
                    this.syncTransactions(transactions, index + 1, failedCount);
                })
                .catch((error) => {
                    console.error('OfflineSync: Failed to sync transaction', index + 1, transaction, error);
                    
                    // Don't stop - continue with next transaction but log the failure
                    transaction.synced = false; // Keep it unsynced so it can be retried
                    failedCount++;
                    this.saveQueue();
                    this.updateStatusIndicator();
                    
                    // Show error but continue (only show first few errors to avoid spam)
                    if (failedCount <= 3) {
                        const errorMsg = `Transaction ${index + 1} failed: ${error}. Continuing...`;
                        this.showSyncNotification(errorMsg, 'warning');
                    }
                    
                    // Wait a bit before continuing
                    setTimeout(() => {
                        this.syncTransactions(transactions, index + 1, failedCount);
                    }, 1000);
                });
        },

        /**
         * Sync single transaction
         */
        syncSingleTransaction: function(transaction) {
            return new Promise((resolve, reject) => {
                // Ensure baseURL is set before making request
                if (!window.baseURL) {
                    window.baseURL = typeof base_url !== 'undefined' ? base_url : (document.getElementById('base_url') ? document.getElementById('base_url').value : '');
                    if (!window.baseURL) {
                        console.error('OfflineSync: window.baseURL not set! Cannot sync transaction.');
                        reject(new Error('baseURL not set'));
                        return;
                    }
                    log('OfflineSync: baseURL set in syncSingleTransaction:', window.baseURL);
                }
                
                // If transaction has a URL, use it (original endpoint)
                // Otherwise use the generic sync endpoint
                let url = transaction.url;
                
                // If no URL stored (old transactions), reconstruct the correct POS endpoint
                if (!url && transaction.type === 'sale') {
                    url = this.reconstructPosUrl(transaction.data);
                }
                
                // Fall back to generic sync URL if still no URL
                if (!url) {
                    url = this.getSyncUrl(transaction.type) || this.config.syncUrl;
                }
                
                log('OfflineSync: Syncing to URL:', url);
                log('OfflineSync: Transaction has URL stored?', !!transaction.url);
                log('OfflineSync: Transaction data:', transaction.data);
                
                // Convert plain object back to FormData for POS endpoint
                const formData = new FormData();
                
                // Add all data fields to FormData
                if (transaction.data) {
                    for (let key in transaction.data) {
                        if (transaction.data.hasOwnProperty(key) && transaction.data[key] !== null && transaction.data[key] !== undefined) {
                            formData.append(key, transaction.data[key]);
                        }
                    }
                }
                
                log('OfflineSync: FormData created, sending request...');
                
                $.ajax({
                    url: url,
                    method: 'POST',
                    data: formData,
                    cache: false,
                    contentType: false, // Let browser set Content-Type with boundary
                    processData: false, // Don't process data - required for FormData
                    dataType: 'text', // Expect text response, not JSON
                    timeout: 30000, // Increase timeout to 30 seconds
                    success: (response) => {
                        log('OfflineSync: Transaction response received:', response);
                        
                        // Check if the response indicates success
                        // POS returns: "success<<<###>>>sales_id<<<###>>>..."
                        if (typeof response === 'string' && response.includes('success')) {
                            log('OfflineSync: Transaction synced successfully');
                            
                            // Refresh item stock to reflect the changes
                            setTimeout(() => {
                                if (typeof get_details === 'function') {
                                    log('OfflineSync: Refreshing POS item stock after sync');
                                    get_details(null, true);
                                }
                            }, 500);
                            
                            resolve({ success: true, message: 'Transaction synced successfully' });
                        } else if (typeof response === 'string' && response.includes('Out of Stock') || response.includes('Stock') || response.includes('stock')) {
                            // Stock-related error
                            console.error('OfflineSync: Stock error detected', response);
                            reject('Stock error: ' + response.substring(0, 200));
                        } else if (typeof response === 'object' && response.success) {
                            resolve(response);
                        } else {
                            // If response doesn't contain 'success', it might still be valid
                            // Check for error strings
                            if (typeof response === 'string' && (response.includes('failed') || response.includes('error'))) {
                                console.error('OfflineSync: Response indicates failure', response);
                                reject('Transaction failed: ' + response.substring(0, 200));
                            } else {
                                // Assume success if no explicit error
                                log('OfflineSync: No explicit success marker, but no error found');
                                resolve({ success: true, message: 'Transaction synced' });
                            }
                        }
                    },
                    error: (xhr, status, error) => {
                        console.error('OfflineSync: AJAX Error occurred');
                        console.error('OfflineSync: Status:', status);
                        console.error('OfflineSync: Error:', error);
                        console.error('OfflineSync: XHR:', xhr);
                        console.error('OfflineSync: Response text:', xhr.responseText ? xhr.responseText.substring(0, 200) : 'No response');
                        
                        // More detailed error message
                        let errorMsg = 'Unknown error';
                        if (status === 'timeout') {
                            errorMsg = 'Request timed out after 30 seconds';
                        } else if (status === 'error' || status === 'parsererror') {
                            errorMsg = 'Network or server error: ' + (error || status);
                            if (xhr.responseText) {
                                errorMsg += ' - ' + xhr.responseText.substring(0, 100);
                            }
                        } else if (xhr.status) {
                            errorMsg = 'HTTP ' + xhr.status + ': ' + (xhr.statusText || error);
                            if (xhr.responseText) {
                                errorMsg += ' - ' + xhr.responseText.substring(0, 100);
                            }
                        }
                        
                        reject(errorMsg);
                    }
                });
            });
        },

        /**
         * Reconstruct POS URL for old transactions without URL stored
         */
        reconstructPosUrl: function(data) {
            // Build the POS save URL with query parameters (same as pos.js line 131)
            let url = window.baseURL + 'pos/pos_save_update';
            
            // Extract query parameters from the data
            const params = [];
            if (data.command) params.push('command=' + encodeURIComponent(data.command));
            if (data.tot_qty) params.push('tot_qty=' + encodeURIComponent(data.tot_qty));
            if (data.tot_amt) params.push('tot_amt=' + encodeURIComponent(data.tot_amt));
            if (data.tot_disc) params.push('tot_disc=' + encodeURIComponent(data.tot_disc));
            if (data.tot_grand) params.push('tot_grand=' + encodeURIComponent(data.tot_grand));
            if (data.paid_amt !== undefined) params.push('paid_amt=' + encodeURIComponent(data.paid_amt));
            if (data.balance !== undefined) params.push('balance=' + encodeURIComponent(data.balance));
            if (data.pay_all !== undefined) params.push('pay_all=' + encodeURIComponent(data.pay_all));
            
            if (params.length > 0) {
                url += '?' + params.join('&');
            }
            
            return url;
        },

        /**
         * Get sync URL for transaction type
         */
        getSyncUrl: function(type) {
            const urls = {
                'sale': window.baseURL + 'pos/pos_save_update', // Changed to use POS endpoint
                'purchase': window.baseURL + 'purchase/purchase_save_and_update',
                'return': window.baseURL + 'sales_return/sales_return_save_and_update',
                'purchase_return': window.baseURL + 'purchase_return/purchase_return_save_and_update'
            };
            return urls[type] || null;
        },

        /**
         * Mark all transactions as synced
         */
        markAllSynced: function() {
            this.queue = this.queue.filter(t => !t.synced);
            this.saveQueue();
        },

        /**
         * Manual sync trigger
         */
        manualSync: function() {
            if (!navigator.onLine) {
                if (this.queue.length > 0) {
                    this.showSyncNotification(this.queue.length + ' transaction(s) will sync when connection is restored. Connect to the internet and click the sync icon again.', 'info');
                } else {
                    this.showSyncNotification('No internet connection. Connect to the internet to sync.', 'error');
                }
                return;
            }

            if (this.queue.length === 0) {
                this.showSyncNotification('No pending transactions to sync', 'info');
                return;
            }

            if (this.syncInProgress) {
                this.showSyncNotification('Sync already in progress. Please wait...', 'info');
                return;
            }

            log('OfflineSync: Manual sync initiated. Queue count:', this.queue.length);
            this.showSyncNotification('Starting sync of ' + this.queue.length + ' transactions...', 'info');
            this.performSync();
        },

        /**
         * Clear old synced transactions
         */
        clearQueue: function() {
            this.queue = this.queue.filter(t => !t.synced);
            this.saveQueue();
            this.updateStatusIndicator();
        },

        /**
         * Delete a specific transaction from the queue by ID
         */
        deleteTransaction: function(transactionId) {
            log('OfflineSyncManager: Deleting transaction', transactionId);
            
            // Filter out the transaction
            const beforeCount = this.queue.length;
            this.queue = this.queue.filter(t => t.id !== transactionId);
            const afterCount = this.queue.length;
            
            if (beforeCount !== afterCount) {
                this.saveQueue();
                this.updateStatusIndicator();
                log('OfflineSyncManager: Transaction deleted successfully');
                return true;
            } else {
                if (DEBUG) console.warn('OfflineSyncManager: Transaction not found in queue');
                return false;
            }
        },

        /**
         * Get transaction by ID
         */
        getTransaction: function(transactionId) {
            return this.queue.find(t => t.id === transactionId);
        },

        /**
         * Get status
         */
        getStatus: function() {
            return {
                isOnline: this.isOnline,
                queueCount: this.queue.length,
                syncInProgress: this.syncInProgress,
                lastSyncTime: localStorage.getItem(this.config.lastSyncKey)
            };
        },

        /**
         * Show sync progress
         */
        showSyncProgress: function(message) {
            // You can enhance this to show a progress bar
            log('OfflineSync: ' + message);
        },

        /**
         * Show sync notification
         */
        showSyncNotification: function(message, type) {
            type = type || 'info';
            const bgColors = {
                'success': '#28a745',
                'error': '#dc3545',
                'info': '#17a2b8'
            };

            const notification = document.createElement('div');
            notification.style.cssText = `
                position: fixed;
                top: 80px;
                right: 20px;
                background: ${bgColors[type] || bgColors.info};
                color: white;
                padding: 15px 20px;
                border-radius: 5px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 9999;
                font-weight: 600;
                animation: slideIn 0.3s ease;
            `;
            notification.textContent = message;
            
            document.body.appendChild(notification);

            setTimeout(() => {
                notification.style.animation = 'slideOut 0.3s ease';
                setTimeout(() => notification.remove(), 300);
            }, 3000);
        }
    };

    // Initialize when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => OfflineSyncManager.init());
    } else {
        OfflineSyncManager.init();
    }

    // Make available globally
    window.OfflineSyncManager = OfflineSyncManager;

    // Add CSS animation
    const style = document.createElement('style');
    style.textContent = `
        @keyframes slideIn {
            from { transform: translateX(400px); opacity: 0; }
            to { transform: translateX(0); opacity: 1; }
        }
        @keyframes slideOut {
            from { transform: translateX(0); opacity: 1; }
            to { transform: translateX(400px); opacity: 0; }
        }
    `;
    document.head.appendChild(style);

})();
