/**
 * Offline/Online Sync Manager for NCS Billing System
 * Tracks transactions done offline and syncs when internet is restored
 */
(function() {
    'use strict';

    const OfflineSyncManager = {
        // Configuration
        config: {
            syncUrl: window.baseURL + 'sync/auto_sync',
            statusUrl: window.baseURL + 'sync/status',
            offlineQueueKey: 'offline_transactions_queue',
            lastSyncKey: 'last_sync_time',
            checkInterval: 5000, // Check every 5 seconds
            autoSyncDelay: 2000 // Delay before auto-sync
        },

        // State
        isOnline: navigator.onLine,
        syncInProgress: false,
        queue: [],

        /**
         * Initialize
         */
        init: function() {
            console.log('OfflineSync: Initializing...');
            
            // Check if system is running on local installation
            var isLocalInstallation = window.location.hostname === 'localhost' || 
                                     window.location.hostname === '127.0.0.1' || 
                                     window.location.hostname.startsWith('192.168.') ||
                                     window.location.hostname === '::1';
            
            // For local installations, always consider online
            if (isLocalInstallation) {
                console.log('OfflineSync: Local installation detected - forcing online state');
                this.isOnline = true; // Force online state
                // Skip setting up interceptors for local
                this.loadQueue();
                return; // Exit early for local installations
            }
            
            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) {
                console.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();
            }
            
            this.setupEventListeners();
            this.startConnectionCheck();
            this.updateStatusIndicator();
            
            if (this.isOnline && this.queue.length > 0) {
                setTimeout(() => this.attemptAutoSync(), this.config.autoSyncDelay);
            }
        },

        /**
         * Setup event listeners
         */
        setupEventListeners: function() {
            window.addEventListener('online', () => {
                console.log('OfflineSync: Connection restored!');
                this.isOnline = true;
                this.updateStatusIndicator();
                if (this.queue.length > 0) {
                    this.attemptAutoSync();
                }
            });

            window.addEventListener('offline', () => {
                console.log('OfflineSync: Connection lost!');
                // Check if system is running on local installation
                var isLocalInstallation = window.location.hostname === 'localhost' || 
                                         window.location.hostname === '127.0.0.1' || 
                                         window.location.hostname.startsWith('192.168.') ||
                                         window.location.hostname === '::1';
                
                // Don't treat as offline on local installations
                if (isLocalInstallation) {
                    console.log('OfflineSync: Local installation - ignoring offline event');
                    this.isOnline = true; // Keep online state for local
                    return;
                }
                
                this.isOnline = false;
                this.updateStatusIndicator();
            });

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

            // Intercept AJAX calls to handle offline failures
            this.setupAjaxInterceptor();
        },

        /**
         * Setup AJAX interceptor to catch failed requests
         */
        setupAjaxInterceptor: function() {
            // Check if system is running on local installation
            var isLocalInstallation = window.location.hostname === 'localhost' || 
                                     window.location.hostname === '127.0.0.1' || 
                                     window.location.hostname.startsWith('192.168.') ||
                                     window.location.hostname === '::1';
            
            // Don't intercept AJAX on local installations - let everything work normally
            if (isLocalInstallation) {
                console.log('OfflineSync: Local installation detected - skipping AJAX interceptor');
                return;
            }
            
            // Save original send method
            const originalSend = XMLHttpRequest.prototype.send;
            const self = this;

            XMLHttpRequest.prototype.send = function(data) {
                // Attach event listeners
                this.addEventListener('error', function() {
                    // Check if local installation
                    var isLocalInstallation = window.location.hostname === 'localhost' || 
                                             window.location.hostname === '127.0.0.1' || 
                                             window.location.hostname.startsWith('192.168.') ||
                                             window.location.hostname === '::1';
                    
                    if (!self.isOnline && !isLocalInstallation) {
                        console.log('OfflineSync: AJAX request failed - offline');
                        // Could queue this request data if needed
                    }
                });

                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() {
            setInterval(() => this.checkConnection(), this.config.checkInterval);
        },

        /**
         * Check connection status
         */
        checkConnection: function() {
            // Simple ping check
            if (this.isOnline && this.queue.length > 0) {
                setTimeout(() => this.attemptAutoSync(), this.config.autoSyncDelay);
            }
        },

        /**
         * 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
            console.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();
            
            console.log('OfflineSync: Transaction queued for retry', transaction);
            console.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
         */
        updateStatusIndicator: function() {
            const badge = document.getElementById('connection-status-badge');
            const icon = document.getElementById('connection-icon');
            const count = document.getElementById('pending-count-left');
            
            if (!badge) return;

            if (this.isOnline) {
                badge.style.background = '#28a745'; // Green
                badge.style.animation = 'none'; // Remove pulse when online
                badge.title = this.queue.length > 0 
                    ? `${this.queue.length} transactions pending sync - Click to sync`
                    : 'Online - All transactions synced';
                
                // Show pending count
                if (count) {
                    if (this.queue.length > 0) {
                        count.textContent = this.queue.length;
                        count.style.display = 'block';
                        count.style.background = '#ff6b6b';
                    } else {
                        count.style.display = 'none';
                    }
                }
            } else {
                badge.style.background = '#dc3545'; // Red
                badge.style.animation = 'pulse 2s infinite'; // Pulse animation when offline
                badge.title = `${this.queue.length} transactions pending - Working offline`;
                
                if (count) {
                    if (this.queue.length > 0) {
                        count.textContent = this.queue.length;
                        count.style.display = 'block';
                        count.style.background = '#ffa500';
                    } else {
                        count.style.display = 'none';
                    }
                }
            }
        },

        /**
         * 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);
                    console.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() {
            if (!this.isOnline || this.syncInProgress || this.queue.length === 0) {
                return;
            }

            console.log('OfflineSync: Attempting auto-sync...');
            this.performSync();
        },

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

            this.syncInProgress = true;
            const unsynced = this.queue.filter(t => !t.synced);
            
            console.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];
            console.log('OfflineSync: Syncing transaction', index + 1, 'of', transactions.length);
            
            this.syncSingleTransaction(transaction)
                .then(() => {
                    console.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) => {
                // 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;
                }
                
                console.log('OfflineSync: Syncing to URL:', url);
                console.log('OfflineSync: Transaction has URL stored?', !!transaction.url);
                console.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]);
                        }
                    }
                }
                
                console.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) => {
                        console.log('OfflineSync: Transaction response received:', response);
                        
                        // Check if the response indicates success
                        // POS returns: "success<<<###>>>sales_id<<<###>>>..."
                        if (typeof response === 'string' && response.includes('success')) {
                            console.log('OfflineSync: Transaction synced successfully');
                            
                            // Refresh item stock to reflect the changes
                            setTimeout(() => {
                                if (typeof get_details === 'function') {
                                    console.log('OfflineSync: Refreshing POS item stock after sync');
                                    get_details(null, true);
                                }
                            }, 500);
                            
                            // Check for pending print request
                            var pendingPrint = sessionStorage.getItem('pending_print');
                            if (pendingPrint) {
                                try {
                                    var printData = JSON.parse(pendingPrint);
                                    // Extract sales_id from response
                                    var responseParts = response.split('<<<###>>>');
                                    if (responseParts.length > 1) {
                                        var sales_id = responseParts[1];
                                        console.log('OfflineSync: Opening print dialog for sales_id:', sales_id);
                                        
                                        // Open print window after short delay
                                        setTimeout(() => {
                                            window.open(window.baseURL + 'pos/print_invoice_pos/' + sales_id, '_blank');
                                            sessionStorage.removeItem('pending_print');
                                        }, 1000);
                                    }
                                } catch (e) {
                                    console.error('OfflineSync: Error handling print request', e);
                                }
                            }
                            
                            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
                                console.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() {
            // Double-check online status
            if (!navigator.onLine) {
                this.showSyncNotification('Cannot sync while offline. Check your internet connection.', '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;
            }

            console.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) {
            console.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();
                console.log('OfflineSyncManager: Transaction deleted successfully');
                return true;
            } else {
                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
            console.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);

})();
